簡體   English   中英

使用C#綁定到WPF中的UserControl

[英]Binding to a UserControl in WPF using C#

前言我作為示例給出的控件是一個較大項目的示例工作。 我已經從Stackoverflow社區獲得了一些幫助,以消除控件中綁定的一些細節。 令人驚訝的是,我在控件的托管表單中遇到綁定問題。

我已經閱讀並研究了DependencyProperty了很多小時。 我在年初不是WPF開發人員,但是由於業務的失敗,我現在要擔任這個職位,並且我認為這是一個艱巨的任務。

問題是我的這里缺少什么:

托管表單的XAML代碼

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:AControl="clr-namespace:AControl;assembly=AControl" x:Class="DependencySampler.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Grid>

    <AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>

</Grid>

背后的代碼

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new viewModelBinding();
        BeSelected =  new modelMain("Yellow", "#FFFFE0");
    }

    public modelMain BeSelected
    { 
        get { return ((viewModelBinding)DataContext).Selected; }
        set { ((viewModelBinding)DataContext).Selected = value; }
    }

}

ViewModel

    public class viewModelBinding :ViewModelBase
{
    modelMain sel = new modelMain("Red", "#FF0000");
    public modelMain Selected
    {
        get { return sel; }
        set { SetProperty(ref this.sel, value, "Selected"); }
    }
}

下一部分是控件本身。

該模型

    public class modelMain:ViewModelBase
{
    public modelMain(string colName, string hexval)
    {
        ColorName = colName;
        HexValue = hexval;
    }

    string colorName;
    public string ColorName
    {
        get { return colorName; }
        set { SetProperty(ref this.colorName, value, "ColorName"); }
    }

    string hexValue;
    public string HexValue
    {
        get { return hexValue; }
        set { SetProperty(ref this.hexValue, value, "HexValue"); }
    }
}

ViewModel

    public class viewModelMain:ViewModelBase
{
    ObservableCollection<modelMain> val = new ObservableCollection<modelMain>();
    public ObservableCollection<modelMain> ColorsList
    {
        get { return val; }
        set { SetProperty(ref this.val, value, "Colors"); }
    }


    modelMain selectedColor;
    public modelMain SelectedColour
    {          
        get{return selectedColor;}
        set { SetProperty(ref this.selectedColor, value, "SelectedColour"); }
    }

    public void SetCurrentColor(modelMain col)
    {
        SelectedColour = this.val.Where(x => x.ColorName == col.ColorName).FirstOrDefault(); 
    }

    public viewModelMain()
    {
        val.Add(new modelMain("Red", "#FF0000"));
        val.Add(new modelMain("Blue", "#0000FF"));
        val.Add(new modelMain("Green", "#008000"));
        val.Add(new modelMain("Yellow", "#FFFFE0"));

        SelectedColour = new modelMain("Blue", "#0000FF");
    }
}

UserControl XAML

<UserControl x:Class="AControl.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" 
         mc:Ignorable="d" 
         d:DesignHeight="32" d:DesignWidth="190">
<Grid>
    <ComboBox x:Name="cboValue"
              SelectionChanged="cboValue_SelectionChanged"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch"
              ItemsSource="{Binding ColorList, RelativeSource={RelativeSource AncestorType=UserControl}}"
              SelectedValue="{Binding SelectedColor, RelativeSource={RelativeSource AncestorType=UserControl}}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="10"
                               Height="10"
                               Margin="5"
                               Background="{Binding ColorName}"/>
                    <TextBlock Width="35"
                               Height="15"
                               Margin="5"
                               Text="{Binding ColorName}"/>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox> 
</Grid>

后面的UserControl代碼

    public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    ObservableCollection<modelMain> colorList = new viewModelMain().ColorsList;
    public ObservableCollection<modelMain> ColorList
    {
        get { return colorList; }
        set { colorList = value; }
    }


    public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(
        "SelectedColor",
        typeof(modelMain),
        typeof(UserControl1),
        new FrameworkPropertyMetadata(
            null, 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            new PropertyChangedCallback(OnSelectedColorChanged),
            new CoerceValueCallback(CoerceSelectedColorCallback)));


    private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UserControl1 uc = (UserControl1)d;
        uc.SelectedColor = (modelMain)e.NewValue;
    }

    private static object CoerceSelectedColorCallback(DependencyObject d, object value)
    {
        return (modelMain)value;
    }


    public modelMain SelectedColor
    {
        get { return (modelMain)GetValue(SelectedColorProperty); }
        set { SetValue(SelectedColorProperty, value); }
    }

    private void cboValue_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var dat = sender as ComboBox;
        SelectedColor = (modelMain)dat.SelectedValue;
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        //var dat = sender as ComboBox;
        ////SelectedColor = (modelMain)dat.SelectedValue;
        //SelectedColor = (modelMain)this.SelectedColor;
    }
}

請注意,在后面的代碼中有未使用的代碼,但是在我用來放置斷點的示例中

我知道UserControl中不應該存在DataContext,因為它排除了宿主形式中的一個。

我期望的問題是托管表格中的這一行就足夠了。

<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>

但這似乎並沒有達到我的預期。 我可以看到BeSelected已初始化,並且它擁有一個值,但是在加載表單時,我期望黃色進入UserControl並設置DependencyProperty SelectedColor。 這沒有發生,為什么以及如何使它發生?

為了使您的示例正常工作,請執行以下操作(大部分情況下,請執行評論者所說的內容):

托管表單的XAML代碼

<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, RelativeSource={RelativeSource AncestorType=Window}}}"/>

模式並不重要,因為MainWindow不實現INPC,也不知道何時((viewModelBinding)DataContext).Selected(因此,BeSelected)被更改。 實際上,就像喬所說的那樣,OneWayToSource不起作用... RelativeSource是必需的,因為BeSelected是MainWindow的屬性,而不是MainWindow的DataContext。

modelMain

modelMain需要實現IEquatable(如Janne所說)。 為什么? 因為BeSelected = new modelMain(...)創建了一個新的modelMain,所以它不是ComboBox的ItemsSource(ColorList)中的項目之一。 新對象可能具有與其中一項相同的屬性值,但是並不能使它們相等(不同的對象=內存中的不同地址)。 IEquatable給您機會來覆蓋它。

public class modelMain : ViewModelBase, IEquatable<modelMain>
{
  ...
  public bool Equals(modelMain other)
  {
    return (HexValue == other.HexValue);
  }
}

viewModelMain的ColorList的設置方法應將屬性名稱為“ Colors”的SetProperty設置為“ ColorsList”。 它沒有被使用,因此不會阻止您的示例工作,但這仍然是錯誤的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM