मैं अपनी टीम के साथ साझा करने के लिए लाइब्रेरी में शामिल करने के लिए कुछ wpf UserControls बनाने की कोशिश कर रहा हूं लेकिन मेरे लिए केवल-पढ़ने के गुण कैसे काम कर रहे हैं, इसमें कुछ गड़बड़ है।

इस प्रश्न के लिए मैंने दो डिपेंडेंसीप्रॉपर्टीज के साथ एक बहुत ही सरल उपयोगकर्ता नियंत्रण बनाया है। एक जो enum पर आधारित है और दूसरा जो चयनित enum के आधार पर क्रिया करता है। बटन जिस शैली का उपयोग करेगा उसे चुनने के लिए enum का उपयोग किया जा रहा है।

आवेदन एक संदर्भ के रूप में एक Wpf उपयोगकर्ता नियंत्रण पुस्तकालय के साथ एक नियमित Wpf अनुप्रयोग है। मुझे संदेह है कि नियंत्रण पुस्तकालय समस्या में योगदान दे रहा है, इसलिए मुझे लगा कि यह उदाहरण के लिए प्रासंगिक था।

डब्ल्यूपीएफ कंट्रोल लाइब्रेरी1

Dictionary1.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfControlLibrary1">
    <Style x:Key="SampleStyle-Font1">
        <Setter Property="TextElement.FontFamily" Value="Wingdings" />
        <Setter Property="TextElement.FontSize" Value="30" />
    </Style>
    <Style x:Key="SampleStyle-Font2">
        <Setter Property="TextElement.FontFamily" Value="Elephant" />
        <Setter Property="TextElement.FontSize" Value="30" />
    </Style>
    <Style x:Key="SampleStyle-Font3">
        <Setter Property="TextElement.FontFamily" Value="Times New Roman" />
        <Setter Property="TextElement.FontSize" Value="30" />
    </Style>
</ResourceDictionary>

UserControl1.xaml:

<UserControl x:Class="WpfControlLibrary1.UserControl1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:local="clr-namespace:WpfControlLibrary1"
            mc:Ignorable="d"
            d:DesignHeight="100" d:DesignWidth="200">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"></ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <UserControl.Template>
        <ControlTemplate>
            <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=Command}">
                <StackPanel>
                    <Label Style="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=ReadOnlyStyle}" Content="{Binding Path=Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}"></Label>
                </StackPanel>
            </Button>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

UserControl1.xaml.cs

namespace WpfControlLibrary1 {
    using System.Windows;
    using System.Windows.Controls;

    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl {
        public enum StyleSelector {
            Style1,
            Style2,
            Style3
        }

        public static DependencyProperty SelectedStyleProperty =
            DependencyProperty.Register("SelectedStyle", typeof(StyleSelector), typeof(UserControl1), new PropertyMetadata(ReadOnlyStyle_Changed));

        private static readonly DependencyPropertyKey ReadOnlyStylePropertyKey =
            DependencyProperty.RegisterReadOnly("ReadOnlyStyle", typeof(Style),
                typeof(UserControl1), null);

        public UserControl1() {
            InitializeComponent();
        }

        public StyleSelector SelectedStyle {
            get => (StyleSelector)GetValue(SelectedStyleProperty);
            set => SetValue(SelectedStyleProperty, value);
        }

        public Style ReadOnlyStyle => (Style)GetValue(ReadOnlyStylePropertyKey.DependencyProperty);

        private static void ReadOnlyStyle_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            if (!(d is UserControl1 userControl1)) {
                return;
            }

            Style style;
            switch (userControl1.SelectedStyle) {
                case StyleSelector.Style1:
                    style = (Style)userControl1.FindResource("SampleStyle-Font1");
                    break;
                case StyleSelector.Style2:
                    style = (Style)userControl1.FindResource("SampleStyle-Font2");
                    break;
                case StyleSelector.Style3:
                    style = (Style)userControl1.FindResource("SampleStyle-Font3");
                    break;
                default:
                    style = (Style)userControl1.FindResource("SampleStyle-Font1");
                    break;
            }

            userControl1.SetValue(ReadOnlyStylePropertyKey, style);
        }
    }
}

डब्ल्यूपीएफ एप्लिकेशन

मेनविंडो.एक्सएमएल:

<Window x:Class="ReadOnlyDependencyPropertiesWithUserControls.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ReadOnlyDependencyPropertiesWithUserControls"
        xmlns:wpfControlLibrary1="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
        mc:Ignorable="d"
        Title="Example" Height="200" Width="400">
    <StackPanel>
        <wpfControlLibrary1:UserControl1 SelectedStyle="Style1" Content="This is the first control"></wpfControlLibrary1:UserControl1>
        <wpfControlLibrary1:UserControl1 SelectedStyle="Style2" Content="This is the second control"></wpfControlLibrary1:UserControl1>
        <wpfControlLibrary1:UserControl1 SelectedStyle="Style3" Content="This is the third control"></wpfControlLibrary1:UserControl1>
    </StackPanel>
</Window>

नीचे दिया गया आउटपुट दिखाता है कि पहला नियंत्रण एक Style नहीं दिखाता है। यदि मैं एप्लिकेशन चलाता हूं, तो इसे लाइव संपादक का उपयोग करके स्टाइल 2 पर स्विच करें और फिर स्टाइल 1 पर वापस जाएं, विंगडिंग्स फ़ॉन्ट लेता है, लेकिन नए सिरे से ऐसा नहीं होता है। यह निश्चित रूप से एक निर्भरता संपत्ति मुद्दे की तरह लगता है, लेकिन जहां तक ​​​​मैं कह सकता हूं कि मेरे पास सेटअप सही है, खासकर जब से अन्य दो नियंत्रण काम करते प्रतीत होते हैं।

The first control should use the WingDings font, but does not

2
Jeff 21 पद 2018, 18:37

1 उत्तर

सबसे बढ़िया उत्तर

निदान

इसके काम न करने का कारण यह है कि आप SelectedStyle प्रॉपर्टी चेंजेड हैंडलर के अंदर ReadOnlyStyle प्रॉपर्टी वैल्यू असाइन करते हैं। चूंकि SelectedStyle StyleSelector प्रकार का है, जो एक enum है, और आप इस संपत्ति के लिए स्पष्ट रूप से डिफ़ॉल्ट मान निर्दिष्ट नहीं करते हैं, इसका डिफ़ॉल्ट मान default(StyleSelector) द्वारा निर्दिष्ट किया जाएगा। ढांचा, जो StyleSelector.Style1 होता है। और यहां तक ​​​​कि अगर आप अपने पहले नियंत्रण पर इस संपत्ति को स्पष्ट रूप से उस मूल्य को निर्दिष्ट करते हैं, तो मूल्य वास्तव में नहीं बदलता है, एर्गो हैंडलर को लागू नहीं किया जाता है, एर्गो ReadOnlyStyle null रहता है, आपको वह मिलता है जो आपको मिलता है (एक Label डिफ़ॉल्ट शैली के साथ)।

समाधान

इसका समाधान करने के लिए, आपको ReadOnlyStyle का प्रारंभिक मान निर्दिष्ट करना चाहिए। लेकिन चूंकि शैलियों को संसाधन शब्दकोश में रखा जाता है, इसलिए आप इसे कंस्ट्रक्टर में नहीं कर सकते। प्रारंभिक मान निर्दिष्ट करने का एक अच्छा बिंदु यह होगा:

protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);
    var style = (Style)userControl1.FindResource("SampleStyle-Font1");
    SetValue(ReadOnlyStylePropertyKey, style);
}

बेहतर उपाय

अपने लक्ष्य को प्राप्त करने का "WPF तरीका" ट्रिगर का उपयोग करना होगा। तो सबसे पहले आप अपने नियंत्रण से अनावश्यक कोड हटा सकते हैं:

public partial class UserControl1 : UserControl
{
    public enum StyleSelector
    {
        Style1,
        Style2,
        Style3
    }

    public static DependencyProperty SelectedStyleProperty =
        DependencyProperty.Register("SelectedStyle", typeof(StyleSelector), typeof(UserControl1));

    public UserControl1()
    {
        InitializeComponent();
    }

    public StyleSelector SelectedStyle
    {
        get => (StyleSelector)GetValue(SelectedStyleProperty);
        set => SetValue(SelectedStyleProperty, value);
    }
}

फिर अपना टेम्प्लेट संशोधित करें:

<ControlTemplate>
    <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=Command}">
        <StackPanel>
            <Label x:Name="PART_Label" Content="{Binding Path=Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}" />
        </StackPanel>
    </Button>
    <ControlTemplate.Triggers>
        <Trigger Property="local:UserControl1.SelectedStyle" Value="Style1">
            <Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font1}" />
        </Trigger>
        <Trigger Property="local:UserControl1.SelectedStyle" Value="Style2">
            <Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font2}" />
        </Trigger>
        <Trigger Property="local:UserControl1.SelectedStyle" Value="Style3">
            <Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font3}" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

यहाँ दो महत्वपूर्ण बातें हैं:

  1. Label में x:Name होना आवश्यक है ताकि इसे Setter.TargetName में संदर्भित किया जा सके
  2. Trigger.Property मान को पूरी तरह से योग्य होना चाहिए, क्योंकि ControlTemplate में TargetType सेट नहीं है।
2
Grx70 24 पद 2018, 12:35