通过CommandParameters

时间:2017-04-24 11:23:06

标签: c# wpf mvvm ioc-container

我有一个Parent ViewModel,绑定到Parent Window。在里面,有一个ItemsControl,它绑定到Child ViewModels的集合。 ItemsControl创建UserControls(子视图),将其DataContext作为ChildViewModel(根据ItemsControl的工作原理自动生成)。

值得注意的是,我使用Castle Windsor作为IoC。 我也尝试通过(当前正在工作)抽象工厂解析子ViewModels,但它没有帮助。我甚至尝试将子ViewModel注册为单身,但仍然 - 在集合中找不到。

所以我把问题问题简化为简单的类实例化。

现在,我想要的是:

每个提醒(UserControl)都有一个Button,代表关闭。 此按钮绑定到父ViewModel,如下所示:

CloseCommand="{Binding ElementName=level1Listener, Path=DataContext.ReminderBoxCloseCommand}"

其中level1ListenerItemsControl的名称。

到目前为止一切正常,UserControls已创建且所有绑定都有效。但是:

  

单击“关闭”按钮时,即使绑定命令执行,也不会从集合中删除ViewModel。看来,任何UserControls返回的ReminderBoxViewModel实例都不存在于集合中 - 但是UserControl甚至出现直接依赖于它们的存在。

     

当我只是删除某个索引处的元素时 - 一切正常。

     

UC如何能够返回与“数据上下文”不同的东西?

这怎么可能,或者我完全错过了什么?

这是我的PhoneWindow视图:

<Window x:Class="NoContact.Views.PhoneWindow"
    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:NoContact.Views"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:avalon="http://icsharpcode.net/sharpdevelop/avalonedit"
    xmlns:usercontrols="clr-namespace:NoContact.UserControls"
    xmlns:viewModels="clr-namespace:NoContact.ViewModels"
    mc:Ignorable="d"
    Title="PhoneWindow" Height="600" Width="980"
    Background="#22282a">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="600" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    <Border Grid.Column="0" Margin="10, 10" Style="{StaticResource phoneWindowBorderStyle}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="80"/>
                <RowDefinition Height="180" />
                <RowDefinition Height="*" />
                <RowDefinition Height="100"/>
            </Grid.RowDefinitions>
            <Border Grid.Row="0" Margin="-1,-1" Style="{StaticResource phoneWindowBorderStyle}">
                <StackPanel Orientation="Horizontal">
                    <Image Margin="15">
                        <Image.Source>
                            <DrawingImage>
                                <DrawingImage.Drawing>
                                    <DrawingGroup>
                                        <GeometryDrawing Brush="#ffcd22"
                                             Geometry="{StaticResource phoneIconGeometry}" />
                                    </DrawingGroup>
                                </DrawingImage.Drawing>
                            </DrawingImage>
                        </Image.Source>
                    </Image>
                    <TextBlock VerticalAlignment="Center" FontSize="30" Style="{StaticResource phoneWindowTextBlockStyle}">Telefon</TextBlock>
                </StackPanel> 
            </Border>

            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0">
                    <DockPanel LastChildFill="False">
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="Top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Imię:</TextBlock>
                            <TextBox Height="30" Margin="46,0,10,0" Style="{StaticResource phoneWindowTextBoxStyle}"></TextBox>
                        </DockPanel>
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="Top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Nazwisko:</TextBlock>
                            <TextBox Height="30" Margin="10,0,10,0" Style="{StaticResource phoneWindowTextBoxStyle}"></TextBox>
                        </DockPanel>
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Data:</TextBlock>
                            <usercontrols:DateTimePicker Height="30" Margin="40,0,10,0" BorderBrush="#ffcd22" BorderThickness="1" Background="#15151a" Foreground="#ffcd22"/>
                        </DockPanel>
                    </DockPanel>
                </Grid>
                <Grid Grid.Column="1">
                    <DockPanel LastChildFill="False">
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="Top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Email:</TextBlock>
                            <TextBox Height="30" Margin="26,0,10,0" Style="{StaticResource phoneWindowTextBoxStyle}"></TextBox>
                        </DockPanel>
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="Top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Telefon:</TextBlock>
                            <TextBox Height="30" Margin="10,0,10,0" Style="{StaticResource phoneWindowTextBoxStyle}"></TextBox>
                        </DockPanel>
                        <DockPanel LastChildFill="True" Margin="10,20,0,0" DockPanel.Dock="top">
                            <TextBlock Style="{StaticResource phoneWindowTextBlockStyle}">Nr. Zamówienia:</TextBlock>
                            <TextBox Height="30" Margin="10,0,10,0" Style="{StaticResource phoneWindowTextBoxStyle}"></TextBox>
                        </DockPanel>
                    </DockPanel>
                </Grid>
            </Grid>
            <Grid Grid.Row="2">
                <avalon:TextEditor Margin="10,10" Style="{StaticResource phoneWindowAvalonEditStyle}" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" WordWrap="True">

                </avalon:TextEditor>
            </Grid>
            <Border Grid.Row="3" Margin="-1,0,-1,-1" Style="{StaticResource phoneWindowBorderStyle}">
                <Grid>
                    <Button Width="170" HorizontalAlignment="Right" Margin="10" Style="{StaticResource flatButtonStyle}">Gotowe</Button>
                    <Button Width="170" HorizontalAlignment="Left" Margin="10" Style="{StaticResource flatButtonStyle}">Anuluj</Button>
                </Grid>
            </Border>
        </Grid>
    </Border>

    <Border Grid.Column="1" Margin="10,10" Style="{StaticResource phoneWindowBorderStyle}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="80" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Border Grid.Row="0" Margin="-1,-1,-1,-1" Style="{StaticResource phoneWindowBorderStyle}">
                <usercontrols:ImageButton x:Name="addButton" Style="{StaticResource addImageButtonUCStyle}" Text="Dodaj Termin" ClickCommand="{Binding Path=AddReminderCommand}">

                </usercontrols:ImageButton>
            </Border>
            <Border Grid.Row="1" Margin="-1,0,-1,-1" Style="{StaticResource phoneWindowBorderStyle}">
                <ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Background="#15151a">
                    <ItemsControl x:Name="level1Listener" ItemsSource="{Binding Path=Reminders, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate DataType="{x:Type viewModels:ReminderBoxViewModel}">
                                <StackPanel>
                                    <usercontrols:ReminderBox VerticalAlignment="Top" Background="#22282a" Foreground="#ffcd22" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                                              AncestorType={x:Type ScrollViewer}}, Path=ActualWidth}" Height="140" CloseCommand="{Binding ElementName=level1Listener, Path=DataContext.ReminderBoxCloseCommand}"
                                                              CommandParameter="{Binding}"/>
                                    <Rectangle Height="1" Margin="10,0" Fill="#ffcd22" />
                                </StackPanel>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ScrollViewer>
            </Border>
        </Grid>
    </Border>
</Grid>

PhoneWindow(查看)代码背后:

namespace NoContact.Views
{
/// <summary>
/// Interaction logic for phoneWindow.xaml
/// </summary>
public partial class PhoneWindow : Window, IView
{
    public IViewModel ViewModel { get; private set; }
    private IWindowManager _windowManager;

    public PhoneWindow(IViewFactory context, IWindowManager windowManager)
    {
        InitializeComponent();

        _windowManager = windowManager;

        var obj = context.Create<IPhoneWindowViewModel>();
        ViewModel = obj;
        this.DataContext = obj;
        context.Release(obj);
    }

    protected override void OnClosed(EventArgs e)
    {
        _windowManager.RemoveFromWindowList(this);
        base.OnClosed(e);
    }
}
}

这是MainViewModel:

public class PhoneWindowViewModel : BindableBase, IPhoneWindowViewModel
{
    private IWindowManager _windowManager;

    private ObservableCollection<IReminderBoxViewModel> _reminders;

    public PhoneWindowViewModel(IWindowManager windowManager)
    {
        _windowManager = windowManager;

        _reminders = new ObservableCollection<IReminderBoxViewModel>();
    }

    public ICommand ReminderBoxCloseCommand { get { return new RelayCommand<ReminderBoxViewModel>(CloseReminderBox); } }
    public ICommand AddReminderCommand { get { return new RelayCommand(AddReminder, () => true); } }

    public ObservableCollection<IReminderBoxViewModel> Reminders
    {
        get { return _reminders; }
        set
        {
            _reminders = value;
            OnPropertyChanged();
        }
    }

    /// <summary>
    /// Delegates closing the window, associated with 
    /// this ViewModel instance.
    /// </summary>
    private void CloseWindow()
    {
        _windowManager.CloseWindow(this);
    }

    /// <summary>
    /// "Closes" the Reminder Box by deleting it from the Collection 
    /// </summary>
    private void CloseReminderBox(ReminderBoxViewModel viewModel)
    {
        Reminders.Remove(viewModel);
        var index = Reminders.IndexOf(viewModel);
        System.Windows.MessageBox.Show(index.ToString());

    }

    /// <summary>
    /// Adds the reminder to the Collection
    /// </summary>
    private void AddReminder()
    {
        Reminders.Add(new ReminderViewModel());
    }

最后,我的userControl代码:

namespace NoContact.UserControls
{
/// <summary>
/// Interaction logic for ReminderBox.xaml
/// </summary>
public partial class ReminderBox : UserControl
{
    #region Dependency Properties

    public Brush CloseButtonBrush
    {
        get { return (Brush)GetValue(CloseButtonBrushProperty); }
        set { SetValue(CloseButtonBrushProperty, value); }
    }

    public new Brush Background
    {
        get { return (Brush)GetValue(BackgroundProperty); }
        set { SetValue(BackgroundProperty, value); }
    }

    public new Brush Foreground
    {
        get { return (Brush)GetValue(ForegroundProperty); }
        set { SetValue(ForegroundProperty, value); }
    }

    public ICommand CloseCommand
    {
        get { return (ICommand)GetValue(CloseCommandProperty); }
        set { SetValue(CloseCommandProperty, value); }
    }

    public object CommandParameter
    {
        get { return (object)GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }

    public static readonly DependencyProperty CloseButtonBrushProperty =
        DependencyProperty.Register("CloseButtonBrush", typeof(Brush), typeof(ReminderBox), new UIPropertyMetadata(null));

    public static readonly new DependencyProperty BackgroundProperty =
       DependencyProperty.Register("Background", typeof(Brush), typeof(ReminderBox), new UIPropertyMetadata(null));

    public static readonly new DependencyProperty ForegroundProperty =
      DependencyProperty.Register("Foreground", typeof(Brush), typeof(ReminderBox), new UIPropertyMetadata(null));

    public static readonly DependencyProperty CloseCommandProperty =
        DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(ReminderBox), new UIPropertyMetadata(null));

    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(ReminderBox), new UIPropertyMetadata(null));

    #endregion



    public ReminderBox()
    {
        InitializeComponent();


    }
}
}

提醒XAML:

<UserControl x:Class="NoContact.UserControls.ReminderBox"
         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:NoContact.UserControls"
         xmlns:usercontrols="clr-namespace:NoContact.UserControls"
         xmlns:helpers="clr-namespace:NoContact.Helpers"
         mc:Ignorable="d" 
         x:Name="ReminderBoxUC"
         d:DesignHeight="130" d:DesignWidth="400">
<Grid>
    <Border Background="{Binding ElementName=ReminderBoxUC, Path=Background}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="0.5*" />
                <RowDefinition Height="0.5*" />
                <RowDefinition Height="1*" />
            </Grid.RowDefinitions>

            <Button Grid.Row="0" Width="20" Height="20" Style="{StaticResource flatButtonStyle}" Background="Transparent" Foreground="Transparent"
                    HorizontalAlignment="Right"
                    VerticalAlignment="Top"
                    Margin="0,10,10,0"
                    Command="{Binding ElementName=ReminderBoxUC, Path=CloseCommand}">
                <Border Name="closeButtonBackgroundBorder" CornerRadius="5" Style="{StaticResource CloseButtonReminderBox_BorderUCStyle}">
                    <Image Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=ActualWidth}"
                       Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=ActualHeight}"
                       HorizontalAlignment="Center" VerticalAlignment="Center">
                        <Image.Source>
                            <DrawingImage>
                                <DrawingImage.Drawing>
                                    <DrawingGroup>
                                        <GeometryDrawing Brush="{Binding ElementName=ReminderBoxUC, Path=CloseButtonBrush}" Geometry="{StaticResource closeIconGeometry}" />
                                    </DrawingGroup>
                                </DrawingImage.Drawing>
                            </DrawingImage>
                        </Image.Source>
                    </Image>
                </Border>
            </Button>

            <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10,0">
                <TextBlock Foreground="{Binding ElementName=ReminderBoxUC, Path=Foreground}"
                           VerticalAlignment="Center" HorizontalAlignment="Left">Przypomnij:
                </TextBlock>
                <RadioButton Name="RemindOnceRadioButton" IsChecked="True"
                                 Foreground="{Binding ElementName=ReminderBoxUC, Path=Foreground}"
                                 Style="{StaticResource RadioButtonStyle}"
                                 VerticalAlignment="Center" Margin="25,0,0,0">1 Raz</RadioButton>
                <RadioButton Name="RemindMultipleRadioButton"   
                             Foreground="{Binding ElementName=ReminderBoxUC, Path=Foreground}"
                                 Style="{StaticResource RadioButtonStyle}"
                                 VerticalAlignment="Center" Margin="25,0,0,0">Wielokrotnie</RadioButton>
            </StackPanel>

            <DockPanel Grid.Row="2"
                            Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}">
                <usercontrols:DateTimePicker Height="25" Margin="10,0" BorderBrush="#ffcd22" BorderThickness="1" Foreground="#ffcd22" Background="#15151a" Width="150" />
                <ComboBox Width="150" Height="25" HorizontalAlignment="Right" Margin="10,0" Style="{StaticResource comboBoxStyle}" ItemsSource="{Binding Source={helpers:EnumBindingSource {x:Type local:TimePeriods}}}"
                          SelectedIndex="0" />
            </DockPanel>
        </Grid>
    </Border>        
</Grid>
<UserControl.Resources>
    <Style TargetType="local:ReminderBox">
        <Setter Property="CloseButtonBrush" Value="#ffcd22" />
        <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=closeButtonBackgroundBorder, Path=IsMouseOver}" Value="True">
                <Setter Property="CloseButtonBrush" Value="#22282a" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

对于ReminderViewModel,它当前为空,除了来自(当前为空)接口IReminderViewModel的继承。

1 个答案:

答案 0 :(得分:1)

您的问题似乎是,您将CommandParameter DP设置为绑定到当前ReminderBoxViewModel,但您没有在ReminderBox中的任何位置使用它。

在提醒XAML中,您正确地将Button的Command绑定到ReminderBox的CloseCommand,而不是将Button的CommandParameter设置为CommandParameter的{​​{1}}你的ReminderBox。

ReminderBox的XAML的相关代码:

<Button ...
        Command="{Binding ElementName=ReminderBoxUC, Path=CloseCommand}"
        CommandParameter"{Binding ElementName=ReminderBoxUC, Path=CommandParameter}">
    ...
</Button>