2016-11-12 115 views
1

我有一个的ListView与它的一些图片,我想是这样的: enter image description here(MVVM/WPF)的视图模型操纵视图元素

我这样做,使用命令CommandParameter用于发送的ListView到我视图模型然后操纵每个图像的宽度高度

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="SelectionChanged"> 
     <i:InvokeCommandAction Command="{Binding MVM.SelectedChangedCommand}" CommandParameter="{Binding ElementName=listView}"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

视图模型:

private void SelectedChangedAction(object param)  
{ 
    ListView s = (ListView)param; 

    double j = 1; 
    for (int i = s.SelectedIndex - 1; i >= 0 && j >= 0; i--, j -= 0.15) 
    { 
     Pic t = (Pic)s.Items[i]; 
     t.Width = 150 * j; 
     t.Height = 250 * j; 
    } 


    j = 1; 
    for (int i = s.SelectedIndex + 1; i < s.Items.Count && j >= 0; i++, j -= 0.15) 
    { 
     Pic t = (Pic)s.Items[i]; 
     t.Width = 150 * j; 
     t.Height = 250 * j; 
    } 
    s.ScrollIntoView(s.Items[s.SelectedIndex]); 
} 

但正如我所说,你可以看到在视图模型,我用的ListViewVM,我认为这是一个违规!那么我怎么能在MVVM这样做? (当然,我想我可以建立一个基于ListView的新控制器,可以做到这一点,但我需要一个简单的解决方案,如XAML或其他)

+0

在您的控件中操作图像大小是UI的功能,所以您完全可以创建UserControl并在其中执行所有布局操作。 – Will

+0

@会是的。但是,正如Nikhil所说,如果没有转换器,我该怎么做? – Mostafa

回答

1

在ViewModel中为SelectedItem创建一个属性。将它绑定到View的ListView中。用转换器设置绑定高度和宽度,然后将所有逻辑移动到那里。

+0

其实我现在正在使用这个,但那只适用于选定的项目。如何根据其索引更改其他项目的宽度和高度? – Mostafa

+0

您可以在转换器中传递整个ListView。 –

+0

工程很棒。谢谢!但我想知道,在**转换器**有使用**视图**和**模型**的知识限制? – Mostafa

0

你真的不应该直接操纵视图模型中的视图组件。相反,应该通过编写一个自定义布局面板来实现此机制,该面板执行视图中元素的大小调整。 This page有关于如何实现这一点的一些很好的信息。

+0

我看了第一张图片,我看到他们只是在SelectedItem上工作。但我想根据他们的索引来处理所有项目。他们也这样做? – Mostafa

1

虽然你已经接受的解决办法,我发现有趣的问题让我发现了以下解决方案:

XAML:

<Window x:Class="SO40564064.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:SO40564064"   
     mc:Ignorable="d" 
     Title="MainWindow" Height="500" Width="600"> 
    <Grid> 
    <ListView Name="TheView" ItemsSource="{Binding Images}"> 
     <ListView.ItemTemplate> 
     <DataTemplate> 
      <local:MyImageBorder Width="{Binding Width}" 
        Height="{Binding Height}" 
        Background="{Binding Color}" 
        IsMouseOverMe="{Binding MouseIsOverMe, Mode=TwoWay}" /> 
     </DataTemplate> 
     </ListView.ItemTemplate> 
     <ListView.ItemsPanel> 
     <ItemsPanelTemplate> 
      <StackPanel Orientation="Horizontal"></StackPanel> 
     </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
    </ListView> 
    </Grid> 
</Window> 

代码背后:

namespace SO40564064 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel(); 
    }  
    } 
} 

ViewModel:

public class ViewModel : INotifyPropertyChanged 
    { 
    public ViewModel() 
    { 
     m_images = new ObservableCollection<MyImage>(
     new MyImage[] { 
      new MyImage() { Color = Brushes.Red, Height = 100, Width = 70 }, 
      new MyImage() { Color = Brushes.Green, Height = 100, Width = 70 }, 
      new MyImage() { Color = Brushes.Blue, Height = 100, Width = 70 }, 
      new MyImage() { Color = Brushes.Yellow, Height = 100, Width = 70 }, 
      new MyImage() { Color = Brushes.Magenta, Height = 100, Width = 70 }, 
      new MyImage() { Color = Brushes.Cyan, Height = 100, Width = 70 } 
      }); 

     foreach (var image in m_images) 
     { 
     image.PropertyChanged += Image_PropertyChanged; 
     } 
    } 

    private void Image_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     switch (e.PropertyName) 
     { 
     case "MouseIsOverMe": 

      var curImage = sender as MyImage; 
      var curIndex = m_images.IndexOf(curImage); 

      if (curImage.MouseIsOverMe) 
      { 
      if (curIndex > 0) 
      { 
       m_images[curIndex - 1].Width *= 1.2; 
       m_images[curIndex - 1].Height *= 1.2; 
      } 
      if (curIndex < m_images.Count - 2) 
      { 
       m_images[curIndex + 1].Width *= 1.2; 
       m_images[curIndex + 1].Height *= 1.2; 
      } 

      m_images[curIndex].Width *= 1.5; 
      m_images[curIndex].Height *= 1.5; 
      } 
      else 
      { 
      if (curIndex > 0) 
      { 
       m_images[curIndex - 1].Width /= 1.2; 
       m_images[curIndex - 1].Height /= 1.2; 
      } 
      if (curIndex < m_images.Count - 2) 
      { 
       m_images[curIndex + 1].Width /= 1.2; 
       m_images[curIndex + 1].Height /= 1.2; 
      } 

      m_images[curIndex].Width /= 1.5; 
      m_images[curIndex].Height /= 1.5; 
      } 
      break; 
     default: 
      break; 
     } 
    } 

    private ObservableCollection<MyImage> m_images; 
    public ObservableCollection<MyImage> Images 
    { 
     get { return m_images; } 
     set 
     { 
     m_images = value; 
     OnPropertyChanged("Images"); 
     } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string property) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); 
    } 
    } 

图片ViewModel类:

public class MyImage : INotifyPropertyChanged 
    { 
    private double m_width; 
    public double Width 
    { 
     get { return m_width; } 
     set 
     { 
     m_width = value; 
     OnPropertyChanged("Width"); 
     } 
    } 

    private double m_height; 
    public double Height 
    { 
     get { return m_height; } 
     set 
     { 
     m_height = value; 
     OnPropertyChanged("Height"); 
     } 
    } 

    private Brush m_color; 
    public Brush Color 
    { 
     get { return m_color; } 
     set 
     { 
     m_color = value; 
     OnPropertyChanged("Color"); 
     } 
    } 

    private bool m_mouseIsOverMe; 
    public bool MouseIsOverMe 
    { 
     get { return m_mouseIsOverMe; } 
     set 
     { 
     m_mouseIsOverMe = value; 
     OnPropertyChanged("MouseIsOverMe"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string property) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); 
    } 
    } 

“图像” 控制子类(这里是边境子类):

using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 

namespace SO40564064 
{ 
    public class MyImageBorder : Border 
    { 
    public MyImageBorder() 
    { 
     IsMouseDirectlyOverChanged += MyImageBorder_IsMouseDirectlyOverChanged; 
    } 

    public bool IsMouseOverMe 
    { 
     get { return (bool)GetValue(IsMouseOverMeProperty); } 
     set { SetValue(IsMouseOverMeProperty, value); } 
    } 

    public static readonly DependencyProperty IsMouseOverMeProperty = 
     DependencyProperty.Register("IsMouseOverMe", typeof(bool), typeof(MyImageBorder), new PropertyMetadata(false)); 

    private void MyImageBorder_IsMouseDirectlyOverChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) 
    { 
     IsMouseOverMe = (bool)e.NewValue; 
    } 
    } 
} 

为了我自己方便,我有一个子类您可以为图像创建子类的边框(或者可以包裹图像的东西)。

该解决方案在鼠标悬停在每个图像时起作用 - 而不是在选择图像时。您可以使用自定义样式将悬停元素的丑陋默认边框设置为样式。