在INotifyPropertyChanged上刷新值转换器

时间:2013-04-07 22:26:17

标签: c# windows-phone-7 ivalueconverter

我知道这里有一些类似的话题,但我无法从他们那里得到任何答案。 我必须在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;
        }


    }

 }

2 个答案:

答案 0 :(得分:2)

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

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


如何重新排列内容:

1)您的'模型'(来自db的实体)应该与您的视图模型不同。为了避免详细说明,它解决了很多问题 - 例如就像你一样。 People getter / setter通常不会以这种方式覆盖(EF经常使用反射来处理w /实体等)。
因此,让PeopleVM(对于单个人或PersonViewModel) - 在那里复制东西 - 并在那里制作INotify - 留下人们只是一个纯粹的实体/ poco w /自动获取/设置。

2)PeopleViewModel相同 - 它与Db过于紧密(这些也是设计指南)。
你不应该重复使用DbContext - 不要保存它 - 它是一个“一次性”对象(并在其中缓存) - 所以使用using()来处理和加载/更新点播。

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

4)XAML - 您的绑定AllPeople,PeopleName是相同的 - 但现在指向视图模型(和名称到VM名称)。
但是你应该将grid绑定到PersonViewModel(旧人)以外的其他内容 - 因为在收集内部时很难“刷新”。
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次更改中强制修改 - 并且你仍然拥有完整的人物(实际上你只需要使用两个,因为你需要的只有Image和TileColor) 。

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

这就是全部:)

短篇版本:
这是proper way并确定可以工作(这取决于您更新Person属性的方式/时间等) - 但您可以先尝试short version - 只需执行multi-binding部分即可人们建模 - 并希望它能够发挥作用。如果不是,你必须做以上所有。

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

<小时/> http://www.thejoyofcode.com/MultiBinding_for_Silverlight_3.aspx

答案 1 :(得分:0)

我明白了(感谢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;
            }

    }

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

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

这会强制值转换器刷新:)