将依赖项属性绑定到viewmodel

时间:2016-08-28 02:59:09

标签: wpf xaml

我正在使用WPF建立一个销售点系统,我遇到了一堵砖墙。

因此,我尝试实现的其中一个组件是“项目面板”(Canvas),它承载“项目按钮”(按钮)。此面板用于添加表示系统中使用的项目的按钮。您可以锁定/解锁面板,以便将新创建的按钮移动到用户喜欢的位置。

我想在Item Buttons上有一个依赖属性,指示按钮是否被锁定(或不是)。创建/锁定/解锁项目按钮是通过使用项目面板中的上下文菜单完成的。

下面我已经包含了我的代码:

ItemPanel.xaml

<Window x:Class="ItemPanel.Views.ItemPanelView"
    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:ItemPanel"
    xmlns:viewModels="clr-namespace:ItemPanel.ViewModels"
    xmlns:views="clr-namespace:ItemPanel.Views"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance Type=viewModels:ItemPanelViewModel, IsDesignTimeCreatable=True}"
    Title="ItemPanelView" 
    Height="800" Width="800">

<ItemsControl ItemsSource="{Binding ItemButtons}">

    <!--ItemPanel-->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas x:Name="ItemPanel" 
                    Background="LightGray"
                    ClipToBounds="True"
                    Focusable="False"
                    Width="400"
                    Height="400">
                <Canvas.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Add Item"
                                  Command="{Binding CreateItemButtonCommand}"/>
                        <MenuItem Header="Lock Panel"
                                  IsCheckable="True"
                                  IsChecked="{Binding IsLocked}"
                                  Command="{Binding LockItemPanelCommand}"
                                  CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"/>
                    </ContextMenu>
                </Canvas.ContextMenu>
            </Canvas>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!--ItemButton-->
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <views:ItemButtonView x:Name="ItemButton" Lock="{Binding DataContext.IsLocked, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>

ItemPanelView.xaml.cs

namespace ItemPanel.Views
{
    /// <summary>
    /// Interaction logic for ItemPanelView.xaml
    /// </summary>
    public partial class ItemPanelView : Window
    {
        public ItemPanelView()
        {
            InitializeComponent();
            DataContext = new ItemPanelViewModel();
        }
    }
}

ItemPanelViewModel.cs

namespace ItemPanel.ViewModels
{
    public class ItemPanelViewModel : ViewModelBase
    {

        private bool _isLocked;

        public ItemPanelViewModel()
        {
            IsLocked = true;
            ItemButtons = new ObservableCollection<ItemButtonViewModel>();

            CreateItemButtonCommand = new DelegateCommand(CreateItemButtonCommandHandler);
            LockItemPanelCommand = new DelegateCommand<bool?>(LockItemPanelCommandHandler);
        }

        public ObservableCollection<ItemButtonViewModel> ItemButtons { get; private set; }

        #region Create ItemButton

        public DelegateCommand CreateItemButtonCommand { get; private set; }

        private void CreateItemButtonCommandHandler()
        {
            //ItemButtonViewModel viewModel = _container.Resolve<ItemButtonViewModel>();
            ItemButtonViewModel viewModel = new ItemButtonViewModel() { Label = Guid.NewGuid()};
            ItemButtons.Add(viewModel);
        }

        #endregion

        #region Lock ItemPanel

        public bool IsLocked
        {
            get
            {
                return _isLocked;                
            }
            set
            {
                _isLocked = value;
                OnPropertyChanged("IsLocked");
            }
        }

        public DelegateCommand<bool?> LockItemPanelCommand { get; private set; }

        public void LockItemPanelCommandHandler(bool? isChecked)
        {
            //if (!isChecked.HasValue)
            //    return;

            //foreach (ItemButtonViewModel itemButton in ItemButtons)
            //{
                //itemButton.IsLocked = IsLocked;
            //}

        }

        #endregion
    }
}

ItemButtonView.xaml

<Button x:Class="ItemPanel.Views.ItemButtonView"
             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:ItemPanel.Views"
             xmlns:viewModels="clr-namespace:ItemPanel.ViewModels"
             mc:Ignorable="d"
             d:DataContext="{d:DesignInstance Type=viewModels:ItemButtonViewModel, IsDesignTimeCreatable=True}"
             Width="100" Height="100"
             Content="{Binding Label}"
             ToolTip="{Binding Label}">

</Button>

ItemButtonView.xaml.cs

namespace ItemPanel.Views
{
    /// <summary>
    /// Interaction logic for ItemButtonView.xaml
    /// </summary>
    public partial class ItemButtonView : Button
    {

        public ItemButtonView()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty LockProperty =
                DependencyProperty.Register("Lock", typeof(bool), typeof(ItemButtonView));

        public bool Lock
        {
            get { return (bool)GetValue(LockProperty); }
            set { SetValue(LockProperty, value); }
        }
    }
}

ItemButtonViewModel.cs

namespace ItemPanel.ViewModels
{
    public class ItemButtonViewModel : ViewModelBase
    {    
        public Guid Label { get; set; }    
    }
}

所以我的问题是,为什么ItemButton视图中的Lock依赖属性没有被ItemPanel IsLocked属性更新。

从我的理解是它应该受到约束......但似乎没有任何东西得到更新。

我真的很感激任何帮助。

由于

1 个答案:

答案 0 :(得分:0)

我在这个例子中使用MVVM Light

所以你有

  • 带有上下文菜单的Canvas:添加内容,锁定移动
  • 内容可以在Canvas中移动(如果已解锁)
  • 一个简单的模型,内容可以是任何东西,交互将被处理
  • 用于为内容分配UI的模板选择器
  • 等...

enter image description here

<强> XAML

<Window x:Class="WpfApplication6.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:WpfApplication6"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d" d:DataContext="{d:DesignInstance local:MyModel}"
        Title="MainWindow" Height="350" Width="525" x:Name="Window">
    <Window.Resources>
        <local:MyTemplateSelector x:Key="MyTemplateSelector" />
        <DataTemplate x:Key="SimpleContentTemplate"   DataType="local:SimpleContent">
            <Grid Width="200" Height="200" Background="DeepSkyBlue">
                <TextBlock Text="{Binding Text}"  HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding Elements}" >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas x:Name="Canvas1" IsItemsHost="True" Background="LightBlue">
                        <Canvas.ContextMenu>
                            <ContextMenu>
                                <MenuItem Header="Add button" Command="{Binding AddButton}" IsEnabled="{Binding IsUnlocked}" />
                                <MenuItem Header="Lock" IsChecked="{Binding IsLocked}" Command="{Binding Lock}" />
                            </ContextMenu>
                        </Canvas.ContextMenu>
                    </Canvas>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate >
                    <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource MyTemplateSelector}">
                        <i:Interaction.Behaviors>
                            <local:MovableBehavior Canvas="{Binding ElementName=Canvas1}" CanMove="{Binding ElementName=Window, Path=DataContext.IsUnlocked }"/>
                        </i:Interaction.Behaviors>
                    </ContentControl>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

代码(C#6)

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;

namespace WpfApplication6
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MyModel();
        }
    }

    public class MyModel : ViewModelBase
    {
        private bool _isLocked;

        public MyModel()
        {
            Lock = new RelayCommand(() =>
            {
                IsLocked = !IsLocked;
                RaisePropertyChanged(() => IsLocked);
            });

            AddButton = new RelayCommand(() => { Elements.Add(new SimpleContent {Text = "Text"}); });

            Elements = new ObservableCollection<object>();
        }

        public ObservableCollection<object> Elements { get; }

        public RelayCommand Lock { get; }

        public RelayCommand AddButton { get; }

        public bool IsUnlocked => !IsLocked;

        public bool IsLocked
        {
            get { return _isLocked; }
            set
            {
                Set(ref _isLocked, value);
                RaisePropertyChanged(() => IsUnlocked);
            }
        }
    }

    public class SimpleContent
    {
        public string Text { get; set; }
    }

    public class MovableBehavior : Behavior<UIElement>
    {
        public static readonly DependencyProperty CanvasProperty = DependencyProperty.Register(
            "Canvas", typeof(Canvas), typeof(MovableBehavior), new PropertyMetadata(default(Canvas)));

        public static readonly DependencyProperty CanMoveProperty = DependencyProperty.Register(
            "CanMove", typeof(bool), typeof(MovableBehavior), new PropertyMetadata(default(bool)));

        private bool _isDragging;

        private Point _point;

        public Canvas Canvas
        {
            get { return (Canvas) GetValue(CanvasProperty); }
            set { SetValue(CanvasProperty, value); }
        }

        public bool CanMove
        {
            get { return (bool) GetValue(CanMoveProperty); }
            set { SetValue(CanMoveProperty, value); }
        }

        protected override void OnAttached()
        {
            AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
            AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
            AssociatedObject.MouseMove += AssociatedObject_MouseMove;
        }

        private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isDragging = true;
            _point = e.GetPosition(AssociatedObject);
            AssociatedObject.CaptureMouse();
        }

        private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _isDragging = false;
            _point = default(Point);
            AssociatedObject.ReleaseMouseCapture();
        }

        private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isDragging || !CanMove)
                return;

            var position = e.GetPosition(Canvas) - _point;
            var parent = VisualTreeHelper.GetParent(AssociatedObject) as ContentPresenter;
            if (parent == null) throw new ArgumentNullException(nameof(parent));
            Canvas.SetLeft(parent, position.X);
            Canvas.SetTop(parent, position.Y);
        }
    }

    public class MyTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var element = container as FrameworkElement;
            if (element != null)
            {
                if (item is SimpleContent)
                {
                    return element.FindResource("SimpleContentTemplate") as DataTemplate;
                }
            }

            return null;
        }
    }
}

你有很多材料可以让你忙碌,我鼓励你看一下我用过的类型的文档!