刷新INotifyPropertyChanged上的值转换器

本文关键字:转换器 INotifyPropertyChanged 刷新 | 更新日期: 2023-09-27 18:07:51

我知道这里有一些类似的话题,但我无法从他们那里得到任何答案。我必须在我的Windows Phone 7应用程序中将网格的背景更新为图像或颜色。我使用我的值转换器来完成此操作,它工作得很好,但我必须重新加载集合,以便更新颜色或图像。

<Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">

转换器接收对象,然后从中获取颜色和图像,这是转换器

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            People myC = value as People;
            string myImage = myC.Image;
            object result = myC.TileColor;
            if (myImage != null)
            {
                BitmapImage bi = new BitmapImage();
                bi.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                ImageBrush imageBrush = new ImageBrush();
                using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (myIsolatedStorage.FileExists(myImage))
                    {
                        using (
                            IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open,
                                                                                              FileAccess.Read))
                        {
                            bi.SetSource(fileStream);
                            imageBrush.ImageSource = bi;
                        }
                    }
                    else
                    {
                        return result;
                    }
                }
                return imageBrush;
            }
            else
            {
                return result;
            }
    }

我需要以某种方式更新/刷新网格标签或值转换器,以便它可以显示最新的更改!

编辑

添加更多代码

模型:

  [Table]
    public class People : INotifyPropertyChanged, INotifyPropertyChanging
    {

        private int _peopleId;
        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int PeopleId
        {
            get { return _peopleId; }
            set
            {
                if (_peopleId != value)
                {
                    NotifyPropertyChanging("PeopleId");
                    _peopleId = value;
                    NotifyPropertyChanged("PeopleId");
                }
            }
        }
        private string _peopleName;
        [Column]
        public string PeopleName
        {
            get { return _peopleName; }
            set
            {
                if (_peopleName != value)
                {
                    NotifyPropertyChanging("PeopleName");
                    _peopleName = value;
                    NotifyPropertyChanged("PeopleName");
                }
            }
        }


        private string _tileColor;
        [Column]
        public string TileColor
        {
            get { return _tileColor; }
            set
            {
                if (_tileColor != value)
                {
                    NotifyPropertyChanging("TileColor");
                    _tileColor = value;
                    NotifyPropertyChanged("TileColor");
                }
            }
        }

        private string _image;
        [Column]
        public string Image
        {
            get { return _image; }
            set
            {
                if (_image != value)
                {
                    NotifyPropertyChanging("Image");
                    _image = value;
                    NotifyPropertyChanged("Image");
                }
            }
        }

        [Column]
        internal int _groupId;
        private EntityRef<Groups> _group;
        [Association(Storage = "_group", ThisKey = "_groupId", OtherKey = "Id", IsForeignKey = true)]
        public Groups Group
        {
            get { return _group.Entity; }
            set
            {
                NotifyPropertyChanging("Group");
                _group.Entity = value;
                if (value != null)
                {
                    _groupId = value.Id;
                }
                NotifyPropertyChanging("Group");
            }
        }

        [Column(IsVersion = true)]
        private Binary _version;
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
        #region INotifyPropertyChanging Members
        public event PropertyChangingEventHandler PropertyChanging;
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }
        #endregion
    }

ViewModel:

public class PeopleViewModel : INotifyPropertyChanged
{
    private PeopleDataContext PeopleDB;
    // Class constructor, create the data context object.
    public PeopleViewModel(string PeopleDBConnectionString)
    {
        PeopleDB = new PeopleDataContext(PeopleDBConnectionString);
    }

    private ObservableCollection<People> _allPeople;
    public ObservableCollection<People> AllPeople
    {
        get { return _allPeople; }
        set
        {
            _allPeople = value;
            NotifyPropertyChanged("AllPeople");
        }
    }
    public ObservableCollection<People> LoadPeople(int gid)
    {
        var PeopleInDB = from People in PeopleDB.People
                           where People._groupId == gid
                           select People;

        AllPeople = new ObservableCollection<People>(PeopleInDB);
        return AllPeople;
    }

    public void updatePeople(int cid, string cname, string image, string tilecol)
    {
        People getc = PeopleDB.People.Single(c => c.PeopleId == cid);
        getc.PeopleName = cname;
        getc.Image = image;
        getc.TileColor = tilecol;
        PeopleDB.SubmitChanges();
    }
    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
    }
    #endregion
}

应用程序页面

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox Margin="0,8,0,0"  x:Name="Peoplelist" HorizontalAlignment="Center"  BorderThickness="4" ItemsSource="{Binding AllPeople}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="{Binding Converter={StaticResource ImageConverter}}" Width="125" Height="125" Margin="6">
                        <TextBlock Name="name" Text="{Binding PeopleName}" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <toolkit:WrapPanel/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Grid>

应用程序页面代码

public partial class PeopleList : PhoneApplicationPage
{
    private int gid;
    private bool firstRun;
    public PeopleList()
    {
        InitializeComponent();
        firstRun = true;
        this.DataContext = App.ViewModel;
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        gid = int.Parse(NavigationContext.QueryString["Id"]);
        if (firstRun)
        {
            App.ViewModel.LoadPeople(gid);
            firstRun = false;
        }

    }
 }

刷新INotifyPropertyChanged上的值转换器

Background="{Binding Converter={StaticResource ImageConverter}}"建议您直接绑定到People 项目(这是您刷新时的问题)。

所以,你应该重新安排一下。将a property改为其他"更高"的数据上下文。


如何重新安排事物:

1) 你的'模型'(实体从数据库)应该不同于你的视图模型。为了避免深入细节,它解决了很多问题——比如你现在。People getter/setter通常不会以这种方式被重写(EF经常使用反射来处理/实体等)。
因此,创建PeopleVM(用于单个People或PersonViewModel) -在那里复制东西-并在那里创建INotify -让People只是一个纯实体/poco/自动获取/设置。

2)同样的PeopleViewModel -它太绑定到Db(这些也是设计指南)。
你不应该重用DbContext -不要保存它-它是一个'一次性'对象(和缓存在里面)-所以使用using()来处理和加载/更新的需求。

3) 用PersonViewModel替换主VM中的People。当您从db加载时,首先将泵入PersonVM -当您以相反的方式保存时。这是MVVM的一个棘手的地方,你经常需要复制/复制-你可以使用一些工具来自动化,或者只是制作复制因子或其他东西。
你的ObservableCollection<People> AllPeople变成了ObservableCollection<PersonViewModel> AllPeople

4) XAML -您的绑定AllPeople, PeopleName是相同的-但现在指向视图模型(和名称到VM名称)。
但是你应该将你的grid绑定到PersonViewModel (old People)以外的东西 -因为在集合内很难"刷新"。
a)创建一个新的单一属性,如ImageAndTileColor -并确保它更新/通知时,任何两个属性的变化。
b)另一个选择是使用MultiBinding -并绑定2,3属性-一个是整个PersonViewModel,就像你一样,加上其他两个属性-例如…

<Grid ...>
    <Grid.Background>
        <MultiBinding Converter="{StaticResource ImageConverter}" Mode="OneWay">
            <MultiBinding.Bindings>
                <Binding Path="Image" />
                <Binding Path="TileColor" />
                <Binding Path="" />
            </MultiBinding.Bindings>
        </MultiBinding>
    </Grid.Background>
    <TextBlock Name="name" Text="{Binding PeopleName}" ... />
</Grid>

这样,当3个更改中的任何一个时,您强制绑定刷新-并且您仍然在那里拥有完整的People(实际上您可以只使用两个,因为您所需要的只是Image和TileColor)。

5)改变你的转换器是multivalue…并读取发送进来的多个值。

就这些了:)

短版:
这是proper way,肯定能工作(这取决于你如何/何时更新Person属性等)-但你可以先尝试short version -只要在People模型上做multi-binding部分-并希望它能工作。如果没有,你就必须做以上所有的事情。

Windows Phone 7:
因为没有MultiBinding
-使用变通方法-它应该非常相似,
-或者将(a)绑定到{Binding ImageAndTileColor, Converter...}。创建新属性(如果您希望在实体/模型中也可以这样做-只需将其标记为[NotMapped()]),这将是一个"复合"属性。


http://www.thejoyofcode.com/MultiBinding_for_Silverlight_3.aspx

我明白了(感谢NSGaga)。我把他的帖子作为答案,以下是我所做的

首先,我需要让转换器接收PeopleId而不是对象本身

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
        int cid = (int)value;
        People myC = App.ViewModel.getPerson(cid);
            string myImage = myC.Image;
            object result = myC.TileColor;
            if (myImage != null)
            {
                BitmapImage bi = new BitmapImage();
                bi.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                ImageBrush imageBrush = new ImageBrush();
                using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (myIsolatedStorage.FileExists(myImage))
                    {
                        using (
                            IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(myImage, FileMode.Open,
                                                                                              FileAccess.Read))
                        {
                            bi.SetSource(fileStream);
                            imageBrush.ImageSource = bi;
                        }
                    }
                    else
                    {
                        return result;
                    }
                }
                return imageBrush;
            }
            else
            {
                return result;
            }
    }

然后我只需要添加call NotifyPropertyChanged("PeopleId")每当我像这样更新Image或TileColor

    private string _tileColor;
    [Column]
    public string TileColor
    {
        get { return _tileColor; }
        set
        {
            if (_tileColor != value)
            {
                NotifyPropertyChanging("TileColor");
                _tileColor = value;
                NotifyPropertyChanged("TileColor");
                NotifyPropertyChanged("PeopleId");
            }
        }
    }

    private string _image;
    [Column]
    public string Image
    {
        get { return _image; }
        set
        {
            if (_image != value)
            {
                NotifyPropertyChanging("Image");
                _image = value;
                NotifyPropertyChanged("Image");
                NotifyPropertyChanged("PeopleId");
            }
        }
    }

强制值转换器刷新:)