WPF - 替换图像后刷新图像源

时间:2015-09-27 17:56:21

标签: c# wpf data-binding .net-4.5 model-binding

在我的应用程序中,我有一个使用ObservableCollection作为ImageSource的网格 我的模型看起来像这样:

    public class Student:INotifyPropertyChanged
    {
        public Student()
        {
        }

        public Student(int id, string firstName, string lastName, int points, bool active = true)
        {
            _id = id;
            _firstName = firstName;
            _lastName = lastName;
            _points = points;
            _active = active;
        }

        private int _id;
        private string _firstName;
        private string _lastName;
        private int _points;
        private bool _active;

        public int Id
        {
            get { return _id; }
            set
            {
                if (value == _id) return;
                _id = value;
                OnPropertyChanged();
            }
        }

        public string FirstName
        {
            get { return _firstName; }
            set
            {
                if (value == _firstName) return;
                _firstName = value;
                OnPropertyChanged();
            }
        }

        public string LastName
        {
            get { return _lastName; }
            set
            {
                if (value == _lastName) return;
                _lastName = value;
                OnPropertyChanged();
            }
        }

        public string Name
        {
            get { return string.Format("{0} {1}", _firstName, _lastName); }
        }

        public int Points
        {
            get { return _points; }
            set
            {
                if (value == _points) return;
                _points = value;
                OnPropertyChanged();
            }
        }

        public string Avatar
        {
            get
            {
                string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                if (appPath == null) return null;
                string imagesPath = Path.Combine(appPath, "Images","Students");
                if (!Directory.Exists(imagesPath)) return null;
                var imagePath = Path.Combine(imagesPath, string.Format("{0}.png", _id));
                if (File.Exists(imagePath)) return imagePath;
                imagePath = Path.Combine(imagesPath, string.Format("{0}.jpg", _id));
                if (File.Exists(imagePath)) return imagePath;
                imagePath = Path.Combine(imagesPath, string.Format("{0}.jpeg", _id));
                if (File.Exists(imagePath)) return imagePath;
                return Path.Combine(imagesPath, "Default.png");
            }
        }

        public bool Active
        {
            get { return _active; }
            set
            {
                if (value == _active) return;
                _active = value;
                OnPropertyChanged();
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

我还将所选学生从网格中存储在变量中 我的XAML看起来像这样:

<DataGrid
    Grid.Column="0"
    Name="StudentsGrid"
    ItemsSource="{Binding Students}"
    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
    CanUserAddRows="True"
    AutoGenerateColumns="False"
    RowEditEnding="StudentsGrid_OnRowEditEnding"
    SelectedItem="{Binding SelectedStudent, Converter={StaticResource SelectedStudentConverter}}">
    <DataGrid.Columns>
        <DataGridTextColumn Width="*" Binding="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" ClipboardContentBinding="{x:Null}" Header="Imię"/>
        <DataGridTextColumn Width="*" Binding="{Binding LastName, UpdateSourceTrigger=PropertyChanged}" ClipboardContentBinding="{x:Null}" Header="Nazwisko"/>
        <DataGridCheckBoxColumn Width="60" Binding="{Binding Active, UpdateSourceTrigger=PropertyChanged}" ClipboardContentBinding="{x:Null}" Header="Aktywna"/>
    </DataGrid.Columns>
</DataGrid>
<Border HorizontalAlignment="Left" Height="120" Margin="10,78,0,0"
            VerticalAlignment="Top" Width="97" BorderBrush="Black" BorderThickness="1">
    <Image Name="Avatar" Source="{Binding SelectedStudent.Avatar, Converter={StaticResource AvatarConverter}}" />
    </Border>
<Button Click="ButtonBase_OnClick" Content="Change avatar" Grid.Column="1" HorizontalAlignment="Right" Margin="0,80,10,0" VerticalAlignment="Top" Width="107"/>

我已经为选定的学生使用了转换器,因为我在尝试添加新行时在网格周围出现红色边框。

和负责按钮点击的代码:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog openfile = new Microsoft.Win32.OpenFileDialog
    {
        DefaultExt = "*.png",
        Filter = "JPG (*.jpg,*.jpeg)|*.jpg;*.jpeg|PNG (*.png)|*.png"
    };
    bool? result = openfile.ShowDialog();
    if (result == true)
    {
        var source = openfile.FileName;
        var ext = Path.GetExtension(source);
        string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (appPath == null) return;
        string imagesPath = Path.Combine(appPath, "Images","Students");
        if (!Directory.Exists(imagesPath)) Directory.CreateDirectory(imagesPath);
        var destination = Path.Combine(imagesPath, string.Format("{0}{1}", _selectedStudent.Id, ext));

        Student old = _selectedStudent;
        SelectedStudent = null;
        File.Copy(source, destination,true);
        SelectedStudent = old;

        var bindingExpression = Avatar.GetBindingExpression(Image.SourceProperty);
        if (bindingExpression != null) bindingExpression.UpdateTarget();
    }
}

和AvatarConverter:

public class AvatarConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.UriSource = new Uri((string)value);
            image.EndInit();

            return image;
            //I've used below code previously, but file was locked
            return new BitmapImage(new Uri((string)value));
        }
        catch
        {
            return new BitmapImage();
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我的想法是显示存储在Images\Student内的当前头像。如果文件存在,则Avatar属性设置为该图像路径,否则我显示Default.png

在当前所选的头像图片旁边,我添加了一个按钮,可让我更新头像。

我无法替换图像文件,因为它正在使用中,但感谢this answer我能够快速解决这个问题。

但我无法更新应用内的图片以显示新来源。我尝试过SelectedStudent并恢复原状,但没有运气。

  1. 如何在磁盘上替换该图像后,为当前学生刷新图像源。
  2. 我应该将“头像”路径移动到转换器还是将其留在模型中?

0 个答案:

没有答案