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

查看:75
本文介绍了在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
    }

ViewModel:

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


    }

 }

推荐答案

背景="{Binding Converter = {StaticResource ImageConverter}}" 建议您直接绑定到 People 项目(刷新时遇到的问题).

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)您的模型"(来自db的实体)应该与您的视图模型不同.为避免细节,它解决了许多问题-例如就像你有. People getters/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中的人.从db加载时,请先将其加载到PersonVM中-另一种方式是保存时.对于MVVM来说,这有点棘手,您通常需要复制/复制-您可以使用某些工具来自动化或仅复制ctor-s或其他东西.
您的 ObservableCollection< People>AllPeople 变为 ObservableCollection< PersonViewModel>所有人

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)将您的Converter更改为IMultiValue ...,并读取发送的多个值.

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

仅此而已:)

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

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天全站免登陆