Mam problemy z zaimplementowaniem niestandardowego DependencyObject:

Potrzebuję konwertera, który ustawia lub usuwa flagę wyliczenia we właściwości powiązanej. Dlatego stworzyłem IValueConverter wyprowadzony z FrameworkElement z dwoma DependencyProperties: Flag (flaga ustawiana/nieustawiona przez konwerter) i Flags (wartość/właściwość do modyfikacji). Nadrzędny UserControl (Name = EnumerationEditor) udostępnia właściwość, z którą powiązany jest konwerter.

ListBox generuje CheckBoxes i wystąpienia konwertera, które są używane do modyfikowania właściwości za pomocą DataTemplate. Każda instancja CheckBox/converter jest używana dla jednej flagi. Używam następującego kodu XAML:

<ListBox Name="Values" SelectionMode="Extended" BorderThickness="1" BorderBrush="Black" Padding="5">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type system:Enum}">

            <DataTemplate.Resources>
                <Label x:Key="myTestResource" x:Shared="False"
                            Content="{Binding}"
                            ToolTip="{Binding Path=Value, ElementName=EnumerationEditor}"
                            Foreground="{Binding Path=Background, ElementName=EnumerationEditor}"
                            Background="{Binding Path=Foreground, ElementName=EnumerationEditor}"/>
                <converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                                    Flag="{Binding}"
                                                    Flags="{Binding Path=Value, ElementName=EnumerationEditor}"/>
            </DataTemplate.Resources>

            <StackPanel Orientation="Horizontal">
                <CheckBox Content="{Binding}" IsChecked="{Binding Path=Value, ElementName=EnumerationEditor, Converter={StaticResource EnumerationConverter}}"/>
                <ContentPresenter Content="{StaticResource myTestResource}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Dziwna rzecz: etykieta działa dobrze, ale konwerter nie. Pojawia się błąd:

System.Windows.Data Błąd: 4: Nie można znaleźć źródła powiązania z odwołaniem „ElementName=EnumerationEditor”. BindingExpression:Ścieżka=Wartość; PozycjaDanych=null; elementem docelowym jest „EnumerationConverter” (Name=''); właściwość docelowa to „Flagi” (typ „Enum”)

Nie rozumiem dlaczego, oprawa jest w zasadzie taka sama...

Oto kod konwertera:

public class EnumerationConverter : FrameworkElement, IValueConverter
{

    #region IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Parity.Space;
    }

    #endregion

    #region public Enum Flag { get; set; }

    public Enum Flag
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagProperty); }
        set { this.SetValue(EnumerationConverter.FlagProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flag.
    /// </summary>
    public static readonly DependencyProperty FlagProperty = DependencyProperty.Register("Flag", typeof(Enum), typeof(EnumerationConverter));

    #endregion

    #region public Enum Flags { get; set; }

    public Enum Flags
    {
        get { return (Enum)this.GetValue(EnumerationConverter.FlagsProperty); }
        set { this.SetValue(EnumerationConverter.FlagsProperty, value); }
    }

    /// <summary>
    /// Dependency property for Flags.
    /// </summary>
    public static readonly DependencyProperty FlagsProperty = DependencyProperty.Register("Flags", typeof(Enum), typeof(EnumerationConverter));

    #endregion

}
1
Korexio 28 lipiec 2011, 12:49
Jest EnumerationEditor częścią twojej kontroli użytkownika, wysłałeś tylko pole listy
 – 
anivas
28 lipiec 2011, 13:08
@anivas: Tak, to sam UserControl. Ma właściwość zależności o nazwie Value typu Enum. Ale jak widać we fragmentach, używam dokładnie tego samego wiązania dla Label.ToolTip, co dla konwertera. Label.ToolTip działa — wyświetla poprawną wartość. Ale konwerter generuje błąd.
 – 
Korexio
28 lipiec 2011, 14:33
Konwertery nie będą częścią drzewa wizualnego, dlatego nie mogły go znaleźć. co próbujesz zrobić?
 – 
anivas
28 lipiec 2011, 14:47
@anivas: Próbuję utworzyć edytor dla właściwości typu enum (z atrybutem Flags). Użytkownik powinien mieć możliwość wyboru flag za pomocą pól wyboru. Konwerter powinien ustawić/wyczyścić określoną flagę we właściwości i określić, czy flaga jest ustawiona.
 – 
Korexio
28 lipiec 2011, 14:55
Lepiej jest z konwerterem wielowartościowym, dzięki czemu możesz wysyłać dowolne wiązanie.
 – 
anivas
28 lipiec 2011, 15:06

2 odpowiedzi

Najlepsza odpowiedź

Wniosek

Postanowiłem rozwiązać problem za pomocą dwóch UserControls; FlagControl i EnumerationEditorControl.

FlagControl ma dwie właściwości zależności

  • Flaga (System.Enum): Określa, która flaga jest ustawiana/czyszczona przez kontrolkę
  • Wartość(System.Enum): powiązana z właściwością/wartością, w której flaga jest ustawiona/wyczyszczona.

EnumerationEditorControl ma jedną właściwość zależności:

  • Wartość(System.Enum): właściwość/wartość, w której ustawione są flagi.

EnumerationEditorControl używa DataTemplate do tworzenia wystąpienia FlagControls. DataTemplate wiąże właściwość FlagControl.Flag z DataContext, a właściwość FlagControl.Value z właściwością EnumerationEditorControl.Value.

W ten sposób nie potrzebuję konwertera, a logika jest wyraźnie oddzielona.

Dzięki za sugestie, komentarze i odpowiedzi!

0
Korexio 29 lipiec 2011, 15:19

Konwerter nie jest FrameworkElement, więc nie powinien dziedziczyć z tej klasy, najlepiej użyć DependencyObject.

Ponieważ konwerter nie znajduje się w żadnym drzewie, wiązanie nie będzie działać, możesz spróbować:

<converters:EnumerationConverter x:Key="EnumerationConverter" x:Shared="False"
                                 Flag="{Binding}"
                                 Flags="{Binding Path=Value, Source={x:Reference EnumerationEditor}}"/>

(Jednak należy to umieścić w Resources UserControl i odnieść się do niego, w przeciwnym razie x:Reference spowoduje cykliczny błąd zależności).

Zauważ, że wiązanie Flag próbuje związać się z DataContext, co może nie działać, ponieważ DataContext może nie być dziedziczone z tych samych powodów, co ElementName i RelativeSource nie będzie działać.

7
H.B. 5 luty 2014, 17:34
Masz całkowitą rację - wiązanie Flag nie działa. Ale mogę użyć rozwiązania x:Reference dla obu elementów i teraz działa. Ale otrzymuję wiele błędów System.Windows.Data (6/23). Muszę znaleźć błędy, ale wskazałeś mi właściwy kierunek, dzięki!
 – 
Korexio
29 lipiec 2011, 10:30