WPF意外行为将ObservableCollection绑定到UserControl

我试图将一堆用户控件绑定到WPF应用程序.这个想法是viewmodel保存服务器名称列表,将其传递给ObservableCollection,然后将该集合绑定到主窗口.

在设计模式下,一切正常!但是,当我运行该应用程序时,绑定似乎中断了,我无所适从地解释了原因.

WPF意外行为将ObservableCollection绑定到UserControl

这是用户控件的XAML:

<UserControl x:Class="ServerMonitor.Wpf.ServerControl"
             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:ServerMonitor.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <local:Server />
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="TextAlignment" Value="Center" />
                <Setter Property="HorizontalAlignment" Value="Stretch" />
            </Style>
        </Grid.Resources>

        <TextBlock Grid.Row="0" Text="{Binding Name}" />

        <TextBlock Grid.Row="8" Text="{Binding LastPolled}" />
    </Grid>
</UserControl>

这是视图模型(ViewModelBase是实现INotifyPropertyChanged的抽象类):

public class MainWindowViewModel : ViewModelBase {

    private List<string> _MachineNames = new List<string> {
        "wschampad",
        // Test
        "T009", "T010", "T011", "T012",
    };
    public List<string> MachineNames {
        get { return _MachineNames; }
        set { _MachineNames = value; OnPropertyChanged("ManchineNames"); }
    }

    private ObservableCollection<Server> _Servers;
    public ObservableCollection<Server> Servers {
        get {
            if (_Servers == null) {
                _Servers = new ObservableCollection<Server>();
                foreach (var machine in MachineNames) {
                    _Servers.Add(new Server {
                        Name = machine, 
                        LastPolled = DateTime.Now, 
                    });
                }
                OnPropertyChanged("Servers");
            }

            return _Servers;
        }
        set { _Servers = value; OnPropertyChanged("Servers"); }
    }
}

这是XAML的主窗口:

<Window x:Class="ServerMonitor.Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ServerMonitor.Wpf"
        Title="Leading Hedge Server Monitor" Height="350" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Menu Grid.Row="0">
            <MenuItem Header="_File">
                <MenuItem Header="_Exit" Name="MenuFileExit" Click="MenuFileExit_Click" />

            </MenuItem>
            <MenuItem Header="_Edit">
                <MenuItem Header="_Options" Name="MenuEditOptions" IsEnabled="False" />
            </MenuItem>
            <MenuItem Header="_Help">
                <MenuItem Header="_About" Name="MenuHelpAbout" IsEnabled="False" />
            </MenuItem>
        </Menu>

        <ItemsControl Grid.Row="1" ItemsSource="{Binding Servers}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="1" Margin="5,5,5,5">
                        <local:ServerControl DataContext="{Binding}" />
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

    </Grid>
</Window>

编辑

将UserControl中的DataContext更改为ignorable可以解决此问题!

<UserControl x:Class="ServerMonitor.Wpf.ServerControl"
             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:ServerMonitor.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <d:UserControl.DataContext>
        <local:Server />
    </d:UserControl.DataContext>

解决方法:

在您的UserControl中摆脱这种情况:

<UserControl.DataContext>
    <local:Server />
</UserControl.DataContext>

这将覆盖从ItemTemplate传递给您的DataContext,最后得到DateTime和string的默认值.

上一篇:c#-旋转形状以跟随wpf中的光标


下一篇:DevExpress WinForm应用开发如何利用MVVM设计模式?这里有答案