我正在尝试使用本机WPF控件实现图像滑块。单击“下一步”或“后退”或“添加新属性”时,PropertyChanged
和SelectedIndex
属性的CurrentImage
事件不会触发。
视图模型:
namespace WpfApplication2.ImageSlider
{
public class ImageList : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<ImageItem> _Images = new ObservableCollection<ImageItem>();
public ObservableCollection<ImageItem> Images
{
get
{ return _Images; }
}
private int _SelectedIndex;
public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs("SelectedIndex");
public int SelectedIndex
{
get { return _SelectedIndex; }
set
{
_SelectedIndex = value;
var handler = PropertyChanged; // value is null
if (handler != null)
{
handler(this, SelectedIndexProperty);
handler(this, CurrentImageProperty);
}
}
}
public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs("CurrentImage"); //Not Firing
private ImageItem _CurrentImage;
public ImageItem CurrentImage //Not Firing
{
get { return _CurrentImage; }
set
{
_CurrentImage = value;
if (Images.Count > 0)
{
CurrentImage =
Images[SelectedIndex];
}
}
}
public void Next()
{
if (SelectedIndex < Images.Count - 1)
SelectedIndex++;
else
SelectedIndex = 0;
}
public void Back()
{
if (SelectedIndex == 0)
SelectedIndex = Images.Count - 1;
else
SelectedIndex--;
}
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
}
}
public ImageList()
{
_canExecute = true;
}
private bool _canExecute;
public void AddNewImage()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.gif, *.png, *.bmp, *.tif) | *.jpg; *.jpeg; *.jpe; *.gif; *.png, *.bmp, *.tif";
dlg.ShowDialog();
if (dlg.FileName != "")
{
Images.Add(new ImageItem() { URI = new Uri(dlg.FileName) });
var handler = PropertyChanged;
if (handler != null)
{
handler(this, CurrentImageProperty);
}
}
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
}
型号:
namespace WpfApplication2.ImageSlider
{
public class ImageItem
{
public Uri URI { get; set; }
private BitmapSource _Source;
public BitmapSource Source
{
get
{
try
{
if (_Source == null) _Source = new BitmapImage(URI);//lazy loading
}
catch (Exception)
{
_Source = null;
}
return _Source;
}
}
public void Save(string filename)
{
var img = BitmapFrame.Create(Source);
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(img);
using (var saveStream = System.IO.File.OpenWrite(filename))
encoder.Save(saveStream);
}
}
}
XAML:
<Window x:Class="WpfApplication2.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:WpfApplication2.ImageSlider"
mc:Ignorable ="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BitmapImage x:Key="NotFound" UriSource="E:\..\NotFound.png"/>
</Window.Resources>
<Window.DataContext>
<local:ImageList/>
</Window.DataContext>
<DockPanel>
<Button Content="<" Click="Back_Click"/>
<Button DockPanel.Dock="Right" Content=">" Click="Next_Click"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay,
TargetNullValue={StaticResource NotFound},
FallbackValue={StaticResource NotFound}}"/>
<Button Content="Add" Command="{Binding ClickCommand}"></Button>
</DockPanel>
</Window>
XAML.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private ImageList _list= new ImageList();
public ImageList list
{
get { return _list; }
set { _list = DataContext as ImageList; } //The count of the images is always 0;
}
private void Next_Click(object sender, RoutedEventArgs e)
{
list.Next();
}
private void Back_Click(object sender, RoutedEventArgs e)
{
list.Back();
}
}
答案 0 :(得分:2)
问题是您使用的按钮与用于显示图像的ImageList
对象不同。您已在XAML中将ImageList
的新实例声明为DataContext
对象。您的代码隐藏确实尝试将此对象分配到_list
字段,该字段支持您用来调用list
和{{1}的Back()
属性方法。
但是这种分配字段的尝试是错误的代码,并且甚至无法工作,因为没有人调用该属性的setter。因此,getter始终返回您在字段初始值设定项中指定的空Next()
对象。
您只需提供一个getter并投射ImageList
值:
DataContext
答案 1 :(得分:1)
你弄错了......这就是为什么它不起作用 属性已更改请勿设置值,仅将信号系统设置为属性的GET值。
尝试将其作为新的ImageListClass
`
public class ImageListFixed : INotifyPropertyChanged
{
#region Fields
private ObservableCollection<ImageItem> images = new ObservableCollection<ImageItem>();
private int selectedIndex;
private ImageItem currentImage;
#endregion Fields
#region Properties
public ObservableCollection<ImageItem> Images
{
get { return images; }
set { images = value; }
}
public int SelectedIndex
{
get { return selectedIndex; }
set
{
if(value < Images.Count && value > -1)
{
selectedIndex = value; OnPropertyChanged();
CurrentImage = Images[selectedIndex];
}
}
}
public ImageItem CurrentImage
{
get { return currentImage; }
set { currentImage = value; OnPropertyChanged(); }
}
#endregion Properties
#region Public Methods
public void Next()
{
SelectedIndex ++;
}
public void Back()
{
SelectedIndex--;
}
#endregion Public Methods
#region Methods
public void AddNewImage()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.gif, *.png, *.bmp, *.tif) | *.jpg; *.jpeg; *.jpe; *.gif; *.png, *.bmp, *.tif";
dlg.ShowDialog();
if(dlg.FileName != "")
{
Images.Add(new ImageItem() { URI = new Uri(dlg.FileName) });
SelectedIndex = Images.Count - 1;
}
}
#endregion Methods
#region Constructors
public ImageListFixed()
{
_canExecute = true;
}
#endregion Constructors
#region Commands
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
}
}
private bool _canExecute;
private ICommand nextCommand;
public ICommand NextCommand
{
get
{
if (nextCommand == null)
{
nextCommand = new CommandHandler(()=> OnNextCommand(), true);
}
return nextCommand;
}
set { nextCommand = value; }
}
private void OnNextCommand()
{
Next();
}
private ICommand backCommand;
public ICommand BackCommand
{
get
{
if(backCommand == null)
{
backCommand = new CommandHandler(() => OnBackCommand(), true);
}
return backCommand;
}
set { backCommand = value; }
}
private void OnBackCommand()
{
Back();
}
#endregion Commands
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
}`
删除窗口中的所有后退代码,并将窗口代码更改为以下内容:
<DockPanel>
<Button Content="<" Command="{Binding BackCommand}"/>
<Button DockPanel.Dock="Right" Content=">" Command="{Binding NextCommand}"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay}"/>
<Button Content="Add" Command="{Binding ClickCommand}"></Button>
</DockPanel>