【问题标题】:Databind in WPFWPF 中的数据绑定
【发布时间】:2016-10-30 19:39:29
【问题描述】:

“编辑”

我想要达到的目标是 -

MainWindow.xaml 包含一个 Button、一个 ComboBox 和一个 ContentControl。 UserControl-A 和 UserControl-C 都包含一个 ContentControl。 UserControl-B 和 UserControl-D 都包含一个 TextBlock。

UserControl-B 将 ContentControl 的内容包含在 用户控制-A。 UserControl-D 将是 ContentControl 的内容 包含在 UserControl-C 中。

UserControl-A 或 UserControl-C 将是 ContentControl 的内容 单击按钮时包含在 MainWindow.xaml 中。

关于改变 Combobox 的 SelectedValue 更新 TextBlock 的 UserControl-B 或 UserControl-D。

“编辑”

除了 MainWindow.xaml、App.xaml 和 App.config 我还有 MainContent1.xaml、MainContent2.xaml、ComboItems.cs 和两个子文件夹 Sub1 和 Sub2,它们每个都包含一个名为 S1.xaml 的文件,在我的项目。

我所有的代码都写在 ComboItems.cs 作为 -

namespace MultiBinding
{ 
public class Item
{
    public string Name { get; set; }
    public int Id { get; set; }
}

public class ComboItems
{
    public ComboItems()
    {
        Items = new List<Item>(3);
        for (int i = 1; i < 4; i++)
            Items.Add(new Item { Id = i, Name = "Name " + i });           
    }
    public List<Item> Items { get; set; }
}

public class ButtonContent : INotifyPropertyChanged
{
    public ICommand MyCommand { get; set; }
    private string _content;

    public ButtonContent()
    {
        _content = "First";
        MyCommand = new Command(Do, CanDo);
    }

    public string Content
    {
        get { return _content; }
        set { _content = value; OnChange("Content"); }
    }

    private bool CanDo(object parameter) => true;       
    private void Do(object parameter) => Content = Content == "First" ? "Second" : "First";
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnChange(string name) => 
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

public class Command : ICommand
{
    private Action<object> Do;
    private Func<object, bool> CanDo;
    public Command(Action<object> Do, Func<object, bool> CanDo)
    {
        this.Do = Do;
        this.CanDo = CanDo;
    }
    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter) => true;
    public void Execute(object parameter) => Do(parameter);
}

public class SomeText
{
    public static string Text1 { get; set; }
    public static string Text2 { get; set; }
}


public class Converter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        switch (values[1].ToString())
        {
            case "1": SomeText.Text1 = SomeText.Text2 = "Selected Item is 1"; break;
            case "2": SomeText.Text1 = SomeText.Text2 = "Selected Item is 2"; break;
            case "3": SomeText.Text1 = SomeText.Text2 = "Selected Item is 3"; break;
        }

        if (values[0].ToString() == "First") return new MainContent1();
        else return new MainContent2();     
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

}

MainWindow.xaml 的内容是 -

<Window x:Class="MultiBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MultiBinding">

<Window.Resources>
    <local:ComboItems x:Key="cboItems" />
    <local:Item x:Key="Item" />
    <local:Converter x:Key="convert" />
    <local:ButtonContent x:Key="content"/>
</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="10*"/>
        <RowDefinition Height="90*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <ComboBox x:Name="combo" 
              DataContext="{Binding Source={StaticResource Item}}"
              ItemsSource="{Binding Path=Items, Source={StaticResource cboItems}}"
              DisplayMemberPath="Name"
              SelectedValuePath="Id"
              SelectedValue="{Binding Path=Id}"/>

    <Button x:Name="butt" Grid.Column="1"
            DataContext="{Binding Source={StaticResource content}}"
            Content="{Binding Path=Content}" 
            Command="{Binding Path=MyCommand}"/>

    <ContentControl Grid.Row="1" Grid.ColumnSpan="2">
        <ContentControl.Content>
            <MultiBinding Converter="{StaticResource convert}">
                <Binding ElementName="butt" Path="Content"/>
                <Binding ElementName="combo" Path="SelectedValue"/>
            </MultiBinding>
        </ContentControl.Content>
    </ContentControl>
</Grid>

MainContent1.xaml 的内容是 -

<UserControl x:Class="MultiBinding.MainContent1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sub="clr-namespace:MultiBinding.Sub1">
<UserControl.Resources>
    <sub:S1 x:Key="s1"/>
</UserControl.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBlock FontSize="20" Text="On Main ContentControl No. 1"/>
    <ContentControl 
        Content="{Binding Source={StaticResource s1}}" 
        Grid.Row="1"/>
</Grid>

MainContent2.xaml 包含与上面完全相同的代码,除了

xmlns:sub="clr-namespace:MultiBinding.Sub2"

文件夹 Sub1 下 S1.xaml 的内容是 -

<UserControl x:Class="MultiBinding.Sub1.S1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:main="clr-namespace:MultiBinding">
<UserControl.Resources>
    <main:SomeText x:Key="MyText"/>
</UserControl.Resources>
<Grid Background="Bisque">
    <TextBlock Text="{Binding Text1, Source={StaticResource MyText}}"  />
</Grid>

文件夹 Sub2 下的 S1.xaml 与 Sub1 文件夹类似,但

<TextBlock Text="{Binding Path=Text2, Source={StaticResource MyText}}" />

以这种方式一切正常。

在 ComboItems.cs 中 SomeText 类的 Text1 和 Text2 属性前面使用 static 关键字是否有问题?

如何在不使用 SomeText 类的静态属性的情况下实现相同的功能?

【问题讨论】:

  • 这需要大量的代码来理解你想要做什么。如果您将问题写在顶部并花一些时间减少源代码的数量,您可能会得到更好的帮助。 HTH
  • 长问题,短答案 - 使用 MVVM 模式。您可以将不同的控件与通用数据模型链接
  • @benPearce 我的回答是否遵循 MVVM 模式?

标签: wpf


【解决方案1】:

我已经从 ComboItems.cs 中删除了“ComboItems and Converter”类,将“ButtonContent”类重命名为“MyCode”并实现如下 -

public class MyCode : INotifyPropertyChanged
{
    //Fields
    private Sub1.S1 _s1;
    private Sub2.S1 _s2;
    private MainContent1 _m1;
    private MainContent2 _m2;
    private object _mainContent;
    private object _subContent;
    private int _selectedIndex;

    //Properties
    public string Text { get; set; }
    public List<Item> Items { get; set; }
    public ICommand MyCommand { get; set; }
    public string Content { get; set; }
    public object MainContent
    {
        get { return _mainContent; }
        set { _mainContent = value; OnChange("MainContent"); }
    }
    public object SubContent
    {
        get { return _subContent; }
        set { _subContent = value; OnChange("SubContent"); }
    }

    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set
        {
            _selectedIndex = value;
            //Action on selection change
            switch (_selectedIndex)
            {
                case 0: Text = "Selected Item is 1"; break;
                case 1: Text = "Selected Item is 2"; break;
                case 2: Text = "Selected Item is 3"; break;
            }
            OnChange("Text");
        }
    }

    //Constructor
    public MyCode()
    {
        Content = "First";
        MyCommand = new Command(Do, CanDo);
        _m1 = new MainContent1();
        _m2 = new MainContent2();
        _s1 = new Sub1.S1();
        _s2 = new Sub2.S1();
        MainContent = _m1;
        SubContent = _s1;
        Items = new List<Item>(3);
        for (int i = 1; i < 4; i++)
            Items.Add(new Item { Id = i, Name = "Name " + i });
        SelectedIndex = 0;
    }

    //Action on Button Click                  
    private void Do(object parameter)
    {
        if(Content == "First")
        {
            MainContent = _m2;
            SubContent = _s2;
            Content = "Second";
        }
        else
        {
            MainContent = _m1;
            SubContent = _s1;
            Content = "First";               
        }
        OnChange("Content");
    }

    private bool CanDo(object parameter) => true;
    //Inotify
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnChange(string name) => 
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

将 MainWindow.xaml 更改为 -

<Window.Resources>
    <local:MyCode x:Key="Code"/>
</Window.Resources>

<Grid DataContext="{Binding Source={StaticResource Code}}">
    <Grid.RowDefinitions...>
    <Grid.ColumnDefinitions...>
    <ComboBox ItemsSource="{Binding Path=Items}"
              DisplayMemberPath="Name"
              SelectedValuePath="Id"
              SelectedIndex="{Binding Path=SelectedIndex}"/>
    <Button x:Name="butt" Grid.Column="1"              
            Content="{Binding Path=Content}" 
            Command="{Binding Path=MyCommand}"/>
    <ContentControl Grid.Row="1" Grid.ColumnSpan="2"
                    Content="{Binding Path=MainContent}"/>
</Grid>

MainContent1.xaml 和 MainContent2.xaml 现在都包含 -

<ContentControl Content="{Binding Path=SubContent}"/>

文件夹 Sub1 和 Sub2 下的 S1.xaml 包含 -

<TextBlock Text="{Binding Path=Text}" />

完成!

【讨论】:

    猜你喜欢
    • 2020-07-20
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 2011-03-24
    • 2011-03-18
    相关资源
    最近更新 更多