WPF XAML数据绑定

本文关键字:数据绑定 XAML WPF | 更新日期: 2023-09-27 18:10:19

我已经玩了一段时间,虽然我可以得到我的设计时数据绑定正确,我似乎不能得到运行时数据绑定。我花了很长时间在网上看了很多数据绑定的各种方法的例子,但还没有遇到一个是这样做的。

我的想法是,使用RelativeSource将窗口绑定到自己,这应该允许我将网格绑定到窗口的属性,即MyWidget。我想我已经用我的设计时间数据复制了这一点,所以我不太确定为什么设计师工作,但是当我运行它时,我只是得到一个空白窗口…

这是我的XAML窗口:

<Window x:Class="XamlPrototype.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:XamlPrototype"
    mc:Ignorable="d"
    Title="MainWindow" Height="646" Width="344"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    d:DataContext="{Binding Source={d:DesignInstance Type=local:DesignTimeWidgetData, IsDesignTimeCreatable=True}}">
<Grid x:Name="MyGrid" 
      DataContext="{Binding MyWidget}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="20" />
        <RowDefinition Height="10" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock FontSize="20" VerticalAlignment="Center" FontWeight="Medium" Grid.Row="0" Margin="20,20,0,0" Text="{Binding Title}" />
    <TextBlock FontSize="12" VerticalAlignment="Top" Grid.Row="1" Margin="20,0,0,0" Text="{Binding Subtitle}" />
    <StackPanel Grid.Row="3">
        <ItemsControl 
            x:Name="ItemsControl"
            ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="20,20,0,0">
                        <Rectangle Stroke="Red" StrokeThickness="5" Width="25" Height="25" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,0,0"></Rectangle>
                        <TextBlock FontSize="20" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,5" Text="{Binding}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Grid>

. .它的代码是:

public partial class MainWindow : Window
{
    public Widget MyWidget { get; set; }
    public MainWindow()
    {
        InitializeComponent();
        InitializeWidgetData();
    }
    private void InitializeWidgetData()
    {
        MyWidget = new Widget
        { 
            Title = "This is the Title",
            Subtitle = "This is the subtitle",
            Items = new List<string>
            {
                "Item Short Name 1",
                "Item Short Name 2",
                "Item Short Name 3",
                "Item Short Name 4",
                "Item Short Name 5",
                "Item Short Name 6",
                "Item Short Name 7",
                "Item Short Name 8"
            }
        };
    }
}

数据上下文:

public class Widget
{
    public string Title { get; set; }
    public string Subtitle { get; set; }
    public List<string> Items { get; set; }
}

和我的设计时间数据:

public class DesignTimeWidgetData
{
    public Widget MyWidget { get; set; }
    public DesignTimeWidgetData()
    {
        MyWidget = new Widget
        { 
            Title = "Design Time Title",
            Subtitle = "Design Time Subtitle",
            Items = new List<string>
            {
                "Design Time Short Name 1",
                "Design Time Short Name 2",
                "Design Time Short Name 3",
                "Design Time Short Name 4",
                "Design Time Short Name 5",
                "Design Time Short Name 6",
                "Design Time Short Name 7",
                "Design Time Short Name 8"
            }
        };
    }
}

更新:

根据HighCore的建议和例子,我做了一些额外的谷歌搜索,我修改了这个项目如下:

App XAML:

<Application x:Class="XamlPrototype.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:XamlPrototype"
         StartupUri="MainWindow.xaml">
<Application.Resources>
    <local:WindowViewModel x:Key="WindowViewModel" />
</Application.Resources>

windows XAML:

<Window x:Class="XamlPrototype.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:XamlPrototype"
    mc:Ignorable="d"
    Title="MainWindow" Height="646" Width="344"        
    DataContext="{StaticResource WindowViewModel}"
    d:DataContext="{Binding Source={d:DesignInstance Type=local:DesignTimeViewModel, IsDesignTimeCreatable=True}}">
<Grid x:Name="MyGrid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="20" />
        <RowDefinition Height="10" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock FontSize="20" VerticalAlignment="Center" FontWeight="Medium" Grid.Row="0" Margin="20,20,0,0" Text="{Binding WindowTitle}" />
    <TextBlock FontSize="12" VerticalAlignment="Top" Grid.Row="1" Margin="20,0,0,0" Text="{Binding WindowSubtitle}" />
    <StackPanel Grid.Row="3">
        <ItemsControl 
            x:Name="ItemsControl"
            ItemsSource="{Binding WindowItems}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="20,20,0,0">
                        <Rectangle Stroke="Red" StrokeThickness="5" Width="25" Height="25" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,0,0"></Rectangle>
                        <TextBlock FontSize="20" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,5" Text="{Binding}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Grid>

. .后面的代码是:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

ViewModel:

public class WindowViewModel : INotifyPropertyChanged
{
    private Widget _widget;
    public string WindowTitle
    {
        get { return _widget.Title ?? "Error!"; }
    }
    public string WindowSubtitle
    {
        get { return _widget.Subtitle ?? "Error!"; }
    }
    public List<string> WindowItems
    {
        get { return _widget.Items ?? new List<string>(); }
    }
    public WindowViewModel()
    {
        //in reality this would come from the Db, or a service perhaps..
        _widget = new Widget
        {
            Title = "This is the Title",
            Subtitle = "This is the subtitle",
            Items = new List<string>
            {
                "Item Short Name 1",
                "Item Short Name 2",
                "Item Short Name 3",
                "Item Short Name 4",
                "Item Short Name 5",
                "Item Short Name 6",
                "Item Short Name 7",
                "Item Short Name 8"
            }
        };
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        // take a copy to prevent thread issues
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

设计时(视图模型)数据:

public class DesignTimeViewModel
{
    public string WindowTitle { get; set; }
    public string WindowSubtitle { get; set; }
    public List<string> WindowItems { get; set; }
    public DesignTimeViewModel()
    {
        var widget = new Widget
        {
            Title = "Design Time Title",
            Subtitle = "Design Time Subtitle",
            Items = new List<string>
            {
                "Design Time Short Name 1",
                "Design Time Short Name 2",
                "Design Time Short Name 3",
                "Design Time Short Name 4",
                "Design Time Short Name 5",
                "Design Time Short Name 6",
                "Design Time Short Name 7",
                "Design Time Short Name 8"
            }
        };
        WindowTitle = widget.Title;
        WindowSubtitle = widget.Subtitle;
        WindowItems = widget.Items;
    }
}

部件数据保持不变

WPF XAML数据绑定

快速解决方案:

在构造函数中交换这些行的顺序:

public MainWindow()
{
    InitializeWidgetData(); // This first
    InitializeComponent();  // This second
}

实际解决方案:

创建一个适当的ViewModel,实现INotifyPropertyChanged绑定,而不是将窗口绑定到自己。