苦苦挣扎将主窗口数据上下文传递到弹出窗口

时间:2016-07-05 17:13:27

标签: c# wpf xaml

模型

OCLMEditorModel // The main model
    OCLMEditorModelData // main data read from XML file (using XMLSerializer)
        List<Meeting> Meetings // List of Meeting objects

除此之外,会议对象包括:

Meeting
    Date
    SpecialEvent

SpecialEvent 的位置是:

SpecialEvent
    Description
    Location
    Type

ModelView

OCLMEditorViewModel // This inherits from INotifyPropertyChanged
    ObservableCollection Meetings // Using the OCLMEditorModel.OCLMEditorModelData.Meetings list as a source
    Meeting // The current meeting object

    _Model = new OCLMEditorModel();
    _MeetingsList = new ObservableCollection<Data.MeetingInfo.Meeting>(_Model.Meetings);
    _Meeting = _Model.MeetingForThisWeek(); // Starts us off correctly (right item in the Meetings list)

视图

这包含会议集合的ComboBox:

<ComboBox x:Name="comboMeetingWeek" ItemsSource="{Binding Meetings}"
    SelectedItem="{Binding Meeting, UpdateSourceTrigger=PropertyChanged}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/Bell.png" Margin="0,0,5,0"
                       Visibility="{Binding IsSpecialEvent, Converter={StaticResource BoolToHiddenConverter}}" Stretch="None"/>
                <TextBlock Text="{Binding DateMeetingAsText}" />
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

所以源是ObservableCollection。并且SelectedItem必须:

public Data.MeetingInfo.Meeting Meeting
{
    get { return _Meeting; }
    set
    {
        // Has the existing meeting object changed at all?
        if(_Meeting != null && _Meeting.IsDirty)
        {
            // Yes, so save it
            _Model.Serialize();
            _Meeting.MarkClean();
        }

        // Now we can update to new value
        if (value != null)
        {
            _Meeting = value;
            OnPropertyChanged("Meeting");
        }
    }
}
private Data.MeetingInfo.Meeting _Meeting;

据我所知,这是对MVVM的正确使用。但现在我想更进一步。我将Image用于ContextMenu

<Image Grid.Column="1" HorizontalAlignment="Right" Source="Images\event_time.png" Margin="2">
    <Image.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Set Special Event" Command="{Binding SetSpecialEventCommand, Mode=OneWay}">
                <MenuItem.Style>
                    <Style TargetType="MenuItem">
                        <Setter Property="IsEnabled" Value="True"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Meeting.IsSpecialEvent}" Value="True">
                                <Setter Property="IsEnabled" Value="False"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </MenuItem.Style>
            </MenuItem>
            <MenuItem Header="Remove Special Event">
                <MenuItem.Style>
                    <Style TargetType="MenuItem">
                        <Setter Property="IsEnabled" Value="False"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Meeting.IsSpecialEvent}" Value="True">
                                <Setter Property="IsEnabled" Value="True"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </MenuItem.Style>
            </MenuItem>
        </ContextMenu>
    </Image.ContextMenu>
</Image>

问题...我们在ComboBox当前选择了Meeting对象...

如果我右键单击并选择设置特殊事件,我将显示一个弹出窗口。这是我有点困惑的地方。我知道我必须使用&#34; UpdateSourceTrigger =明确&#34;在弹出窗口内,然后在OK按钮中执行更新(特殊事件描述,位置,类型)。

我的弹出窗口有问题。 XAML:

<Window x:Class="OCLMEditor.SpecialEventWindow"
        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:OCLMEditor"
        mc:Ignorable="d"
        Title="SpecialEventWindow" Height="300" Width="300">
    <Grid>
        <TextBox x:Name="textDescription" HorizontalAlignment="Left" Height="23" Margin="38,49,0,0" TextWrapping="Wrap"/>
    </Grid>
</Window>

_SetSpecialEventCommand = new DelegateCommand<string>(
    (s) =>
    {
        SpecialEventWindow windowEvent = new SpecialEventWindow();
        windowEvent.DataContext = _Meeting.SpecialEvent;
        windowEvent.ShowDialog();
    },
    (s) => true);

然而,在弹出窗口的XAML编辑器中,它认为它没有DataContext。所以它不允许我将文本框绑定到其中一个属性。

更新

我不确定提出的评论,因为他们显然错过了设置DataContext的代码。但很容易错过。它就在那里。 :)

_SetSpecialEventCommand = new DelegateCommand<string>(
    (s) =>
    {
        SpecialEventWindow windowEvent = new SpecialEventWindow();
        windowEvent.DataContext = _Meeting.SpecialEvent;
        windowEvent.ShowDialog();
    },
    (s) => true);

工作。但我得到的是,当我在代码中设置datacontext时,XAML编辑器似乎并不知道它。因此,当我点击控件并转到绑定时......它不会显示出来。

DataContext

我的主窗口有:

MainWindow

因此它显示了活动数据上下文,我可以使用IDE来浏览绑定。但不是在这个弹出窗口。我必须在代码编辑器中手动完成所有操作。

1 个答案:

答案 0 :(得分:2)

您在运行时给弹出窗口drives,但不是在设计时。 IDE不够智能,无法通过分析代码来弄清楚您希望它做什么。

你的主窗口在设计时有一个DataContext的原因是因为你在XAML 中给它一个声明性的,这不需要任何深入的洞察IDE的部分来计算你的欲望是什么;你只是设置一个属性,在设计时发生 的事情:

DataContext

使用<Window.DataContext> <local:OCLMEditorViewModel /> </Window.DataContext> 实例初始化主窗口的DataContext属性,这是您在“新建”按钮旁边的属性中看到的属性。你没有在弹出窗口中看到它,因为你没有在弹出窗口的XAML中那样做。那是因为您在运行时使用特定的预先存在的OCLMEditorViewModel实例设置其DataContext

有两种方法可以在这里得到你想要的东西:首先,“正确”的方式,即使用SpecialEvent可忽略的属性:

d:DataContext

这需要<Window ... xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=local:SpecialEvent, IsDesignTimeCreatable=True}" ... > 拥有默认构造函数。它可以在detects that it's been instantiated at design time(或不是)时进行特殊的“模拟数据”初始化。

更简单(但不是很好),在您的情况下,您可以像在主窗口中那样实例化它:

SpecialEvent

那将在设计时为您打字<Window.DataContext> <local:SpecialEvent /> </Window.DataContext> 。在运行时,显示对话框的命令将使用从DataContext获取的特定实例替换该垃圾实例,因为所有XAML内容都是在_Meeting.SpecialEvent的构造函数完成时完成的。