刷新 INotifyPropertyChanged 上的值转换器 [英] refreshing Value Converter on INotifyPropertyChanged

查看:22
本文介绍了刷新 INotifyPropertyChanged 上的值转换器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know there are some similar topics here but I couldn't get any answer from them. I have to update background of a grid to either an image or a colour in my Windows Phone 7 app. I do this using my value converter , it works fine but I'd have to reload the collection so it updates the colour or image.

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

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

The converter receives the object then gets the color and image from it, here is the converter

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;
            }

    }

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

I need to somehow update/refresh the grid tag or the value converter so that it can show the latest changes !

编辑

添加了更多代码

模型:

  [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
    }

视图模型:

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;
        }


    }

 }

推荐答案

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

Background="{Binding Converter={StaticResource ImageConverter}}" suggests you bind directly to People item (which is your problem when refreshing).

所以,你应该重新排列一下.将该属性改为其他一些更高"的数据上下文.

So, you should rearrange a bit. Make that a property of some other 'higher' data context instead.

如何重新排列事物:

1) 您的模型"(来自数据库的实体)应该与您的视图模型不同.为了避免深入细节,它解决了很多问题 - 例如就像你有.People getter/setter 通常不会以这种方式覆盖(EF 通常使用反射来处理实体等).
因此,制作 PeopleVM(用于单个 People 或 PersonViewModel) - 在那里复制东西 - 并在那里制作 INotify - 让 People 只是一个带有自动获取/设置的纯实体/poco.

1) your 'model' (entity from db) should be different than your view-model. To avoid going into details, it solves lot of problems - e.g. like you're having. The People getters/setters are not normally overriden in that way (EF often uses reflection to deal w/ entities etc.).
So, make PeopleVM (for single People or PersonViewModel) - copy things in there - and make INotify in there - leave People just a pure entity/poco w/ automatic get/set.

2) 与 PeopleViewModel 相同 - 它与 Db 紧密相关(这些也是设计指南).
你不应该重用 DbContext - 不要保存它 - 它是一个一次性"对象(并缓存在里面) - 所以使用 using() 来处理和按需加载/更新.

2) Same for the PeopleViewModel - it's too tied-up to the Db (these are also design guidelines).
You shouldn't reuse the DbContext - don't save it - it's a 'one off' object (and cached inside) - so use using() to deal with and load/update on demand.

3) 用 PersonViewModel 替换主 VM 中的 People.当您从 db 加载时,首先将泵送入 PersonVM - 当您以另一种方式保存时.这对于 MVVM 来说是一个棘手的问题,您经常需要复制/复制 - 您可以使用一些工具来实现自动化,或者只是制作复制 ctor-s 或其他东西.
你的 ObservableCollectionAllPeople 变成 ObservableCollection;所有人

3) Replace People in your main VM with PersonViewModel. When you load from db, pump up into the PersonVM first - when you're saving the other way around. That's a tricky bit with MVVM, you often need to copy/duplicate - you could use some tool for that to automate or just make copy ctor-s or something.
Your ObservableCollection<People> AllPeople becomes ObservableCollection<PersonViewModel> AllPeople

4) XAML - 您绑定的 AllPeople、PeopleName 是相同的 - 但现在指向视图模型(以及名称到 VM 名称).
但是您应该将您的 grid 绑定到 PersonViewModel(老人们) 以外的其他内容 - 因为在集合中很难刷新".
a) 创建一个新的单一属性,例如 ImageAndTileColor - 并确保它在/当两个属性中的任何一个发生更改时更新/通知.
b) 另一种选择是使用 MultiBinding - 并绑定 2、3 个属性 - 一个是整个 PersonViewModel 就像你一样,加上其他两个属性 - 例如..

4) XAML - your binding AllPeople, PeopleName is the same - but that points now to view-models (and Name to VM Name).
But you should bind your grid to something other than PersonViewModel (old People) - as that is hard to 'refresh' when inside the collection.
a) Make a new single property like ImageAndTileColor - and make sure it updates/notifies on / when any of the two properties change.
b) The other option is to use MultiBinding - and bind 2, 3 properties - one being the whole PersonViewModel like you have and plus those other two properties - e.g...

<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).

That way you force the binding to refresh when any of the 3 changes - and you still have your full People in there (actually you could just use two as all you need is Image and TileColor).

5) 将您的转换器更改为 IMultiValue... 并读取发送的多个值.

5) Change your Converter to be IMultiValue... and to read multiple values sent in.

就是这样:)

简短版本:
这是正确的方式并且肯定会起作用(这取决于您如何/何时更新 Person 属性等)-但是您可以先尝试 short version - 只需执行multi-binding 在 People 模型上的一部分 - 希望它能起作用.如果没有,您必须执行上述所有操作.

SHORT VERSION:
That was the proper way and certain to work (it depends on how/when you update Person properties etc.) - but you could try the short version first - just do the multi-binding part on the People model - and hope it'd work. If it doesn't you have to do all the above.

Windows Phone 7:
由于没有 MultiBinding...
- 使用解决方法 - 应该非常相似,
- 或者使用上面的 (a) - 将网格绑定到 {Binding ImageAndTileColor, Converter...}.创建新属性(如果您愿意,可以在实体/模型中执行相同操作 - 只需将其标记为 [NotMapped()]),这将是一个复合"属性.

Windows Phone 7:
Since there is no MultiBinding...
- Use the workaround - it should be quite similar,
- Or go with the (a) above - bind grid to {Binding ImageAndTileColor, Converter...}. Make new property (you can do the same if you wish in the entity/model - just mark it as [NotMapped()]) which would be a 'composite' one.


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

这篇关于刷新 INotifyPropertyChanged 上的值转换器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆