Binding Properties not updating (1 Viewer)

sccrgoalie1

Portal Pro
September 12, 2013
109
165
38
Home Country
United States of America United States of America
Hello,

I'm slowly learning the new MP2 development and I'm having an issue with Binding that I can figure out. I know my model is bound correctly because when I set the property on first load it works just fine. The problem is when I try to update that property later nothing happens. Here's the relevant code:

XAML
XML:
 <Grid x:Name="Picture1Grid" Margin="{Binding Path=Picture1GridMargin}">
        <Grid.RenderTransform>
            <TransformGroup>
                            <RotateTransform CenterX="100" CenterY="75" Angle="0" />
                            <ScaleTransform ScaleX="1" ScaleY="1"/>
                        </TransformGroup>
        </Grid.RenderTransform>
            <Border x:Name="Picture1Border" BorderBrush="White"
                    BorderThickness="10" MaxWidth="{Binding Path=Picture1Width}"
                    MaxHeight="{Binding Path=Picture1Height}"
                    HorizontalAlignment="Left" VerticalAlignment="Top" >
            <Image Source ="{Binding Path=Picture1}" Stretch="Uniform"/>
        </Border>
        <Label x:Name="Picture1Label" Content="{Binding Path=Picture1Date}"
              HorizontalAlignment="Center" VerticalAlignment="Bottom"
              Color="{Binding Path=Picture1DateColor}" FontSize="8"/>
    </Grid>

CS
C#:
protected readonly AbstractProperty _picture1Property;
    protected readonly AbstractProperty _picture1GridMargin;
    protected readonly AbstractProperty _picture1Date;
    protected readonly AbstractProperty _picture1DateColor;
    protected readonly AbstractProperty _picture1Width;
    protected readonly AbstractProperty _picture1Height;

public MPPhotoSlideshowModel()
    {
      try
      {
        // In models, properties will always be WProperty instances. When using SProperties for screen databinding,
        // the system might run into memory leaks.
        log = new Log(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\Team MediaPortal\MP2-Client\Log", "MPPhotoSlideshow", "log", LogType.Debug);
        _helloStringProperty = new WProperty(typeof(string), HELLOWORLD_RESOURCE);
        _picture1Property = new WProperty(typeof(object), null);
        _picture1Date = new WProperty(typeof(string), null);
        _picture1GridMargin = new WProperty(typeof(object), null);
        _picture1DateColor = new WProperty(typeof(object), null);
        _picture1Width = new WProperty(typeof(object), null);
        _picture1Height = new WProperty(typeof(object), null);
        LoadSettings();
        LoadPage();
      }
      catch (Exception ex)
      {
        if (log != null)
        {
          log.writeLog(ex.ToString(), LogInfoType.Error);
        }
      }
    }

public string Picture1Date
    {
      get { return (string)_picture1Date.GetValue(); }
      set { _picture1Date.SetValue(value); }
    }
    public object Picture1
    {
      get { return (object)_picture1Property.GetValue(); }
      set { _picture1Property.SetValue(value); }
    }
    public object Picture1GridMargin
    {
      get { return (object)_picture1GridMargin.GetValue(); }
      set { _picture1GridMargin.SetValue(value); }
    }
    public object Picture1DateColor
    {
      get { return (object)_picture1DateColor.GetValue(); }
      set { _picture1DateColor.SetValue(value); }
    }
    public object Picture1Height
    {
      get { return (object)_picture1Height.GetValue(); }
      set { _picture1Height.SetValue(value); }
    }
    public object Picture1Width
    {
      get { return (object)_picture1Width.GetValue(); }
      set { _picture1Width.SetValue(value); }
    }
private void LoadPage()
    {
      try
      {
        PhotoTemplate template = _photoTemplates[_templateRnd.Next(_photoTemplates.Count)];
        if (template.Photos[0].Enabled)
        {
          Picture picture1FileName;
          if (template.Photos[0].Image.Height > template.Photos[0].Image.Width)
          {
            picture1FileName = _verticalPictures[_verticalRnd.Next(_verticalPictures.Count)];
          }
          else
          {
            picture1FileName = _horizontalPictures[_horizontalRnd.Next(_horizontalPictures.Count)];
          }
          //log.writeLog(String.Format("MPSlideshow.LoadPage() - Setting new file name {0}",picture1FileName.FilePath), LogInfoType.Debug);
          Picture1 = picture1FileName.FilePath;
          Picture1GridMargin = String.Format("{0},{1},{2},{3}", template.Photos[0].Image.posX, template.Photos[0].Image.posY, 0, 0);
          Picture1Date = picture1FileName.DateTaken.ToString("d");
          Picture1DateColor = template.Photos[0].Label.TextColor;
          Picture1Width = template.Photos[0].Image.Width;
          Picture1Height = template.Photos[0].Image.Height;
        }
      }
      catch (Exception ex)
      {
        log.writeLog(ex.ToString(), LogInfoType.Error);
      }
    }

Any idea why this isn't updating. The LoadPage() method is called every 10 seconds via a timer tick event.
 
Last edited by a moderator:

Holzi

Super Moderator
  • Team MediaPortal
  • April 21, 2010
    7,934
    2,235
    Ba-Wü
    Home Country
    Germany Germany
    It is always nice to have people which are interested in MP2. Hopefully some MP2 dev can help you.
    Thanks! :)
     

    BigGranu

    Retired Team Member
  • Premium Supporter
  • February 7, 2013
    240
    202
    53
    Home Country
    Germany Germany
    XML:
    <Label x:Name="Picture1Label" Content="{Binding Path=Picture1Date}"
                  HorizontalAlignment="Center" VerticalAlignment="Bottom"
                  Color="{Binding Path=Picture1DateColor}" FontSize="8"/>

    Use "Mode=TwoWay"

    XML:
    <Label x:Name="Picture1Label" Content="{Binding Path=Picture1Date, Mode=TwoWay}"
                  HorizontalAlignment="Center" VerticalAlignment="Bottom"
                  Color="{Binding Path=Picture1DateColor}" FontSize="8"/>

    I, hope it works.
     
    Last edited by a moderator:

    morpheus_xx

    Retired Team Member
  • Team MediaPortal
  • March 24, 2007
    12,073
    7,459
    Home Country
    Germany Germany
    The cause is simple, I had to learn this difference to WPF myself:
    In MPF you also need to expose the AbstractProperty for xaml binding.

    If your property is named "Width" you have to expose "public AbstractProperty WidthProperty".

    Another important note: from models use only WProperty (weak references). SProperty is only allowed for controls.

    For an example and comments take look at the HelloWorldModel:
    C#:
        /// <summary>
        /// This sample property will be accessed by the hello_world screen. Note that the data type must be the same
        /// as given in the instantiation of our backing property <see cref="_helloStringProperty"/>.
        /// </summary>
        public string HelloString
        {
          get { return (string) _helloStringProperty.GetValue(); }
          set { _helloStringProperty.SetValue(value); }
        }
    
        /// <summary>
        /// This is the dependency property for our sample string. It is needed to propagate changes to the skin.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If the screen databinds to the <see cref="HelloString"/> property in a binding mode which will propagate data
        /// changes from the model to the skin (OneWay, TwoWay), the SkinEngine will attach a change handler to this property
        /// and react to changes.
        /// </para>
        /// <para>
        /// In other words: For each property <c>Xyz</c>, which should be able to be attached to, there must be an
        /// <see cref="AbstractProperty"/> with name <c>XyzProperty</c>.
        /// Only if <c>XyzProperty</c> is present in the model, value changes can be propagated to the skin.
        /// </para>
        /// </remarks>
        public AbstractProperty HelloStringProperty
        {
          get { return _helloStringProperty; }
        }
     
    Last edited:

    sccrgoalie1

    Portal Pro
    September 12, 2013
    109
    165
    38
    Home Country
    United States of America United States of America
    Thank you!! I can't believe I missed that. I've been using hello world as my base template. I made the change and now it's working properly!
     

    sccrgoalie1

    Portal Pro
    September 12, 2013
    109
    165
    38
    Home Country
    United States of America United States of America
    Some more binding issues, I'm attempting to improve my plugin by using an ItemsControl instead of explicitly adding each item in XAML. I've tested the code below in Blend and it works, so I'm pretty sure my binding is the issue. I've been trying to get this working for about a week, so any help would be appreciated. I've been trying use the weather model as my source. Also, I did add the ObservableCollection to MP2 as shown in this branch https://github.com/MediaPortal/MediaPortal-2/tree/FEAT_ObservableCollections

    Here's the code:

    xaml
    Code:
    <Screen xmlns="www.team-mediaportal.com/2008/mpf/directx"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Context="{Model Id=C6B0FA5A-288E-405A-A5D5-AA66CC0AA327}">
        <Screen.Resources>
            <Model x:Key="Model" Id="C6B0FA5A-288E-405A-A5D5-AA66CC0AA327"/>
        </Screen.Resources>
        <Canvas DataContext="{Binding Source={StaticResource Model}}">
            <Canvas.Background>
                <ImageBrush ImageSource="{Binding Path=SlideshowBackgroundProperty}" Stretch="Fill"/>
            </Canvas.Background>
            <HeaderedItemsControl ItemsSource="{Binding Path=PictureList}">
                <HeaderedItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas Background="Green"/>
                    </ItemsPanelTemplate>
                </HeaderedItemsControl.ItemsPanel>
                <HeaderedItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Canvas.Left" Value="{Binding Path=Left}"/>
                        <Setter Property="Canvas.Top" Value="{Binding Path=Top}"/>
                    </Style>
                </HeaderedItemsControl.ItemContainerStyle>
                <HeaderedItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Image Source ="{Binding Path=PictureImage}" Stretch="Uniform" MaxWidth="50" MaxHeight="50"/>
                    </DataTemplate>
                </HeaderedItemsControl.ItemTemplate>
            </HeaderedItemsControl>       
        </Canvas>
    </Screen>

    Binding Picture
    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    
    namespace MPPhotoSlideshow
    {
      public class BindingPicture:INotifyPropertyChanged
      {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
          if (PropertyChanged != null)
          {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
          }
        }
        private int _left;
        public int Left
        {
          get { return _left; }
          set
          {
            if (_left != value)
              _left = value;
            NotifyPropertyChanged("Left");
          }
        }
        private int _top;
        public int Top
        {
          get { return _top; }
          set
          {
            if (_top != value)
              _top = value;
            NotifyPropertyChanged("Top");
          }
        }
        private string _pictureImage;
        public string PictureImage
        {
          get { return _pictureImage; }
          set
          {
            if (_pictureImage != value)
              _pictureImage = value;
            NotifyPropertyChanged("PictureImage");
          }
        }
    }

    Model

    Code:
    protected readonly AbstractProperty _slideshowBackgroundProperty;
    private ObservableCollection<BindingPicture> _pictureList = null;
    public ObservableCollection<BindingPicture> PictureList;
    public string SlideshowBackground
        {
          get { return (string)_slideshowBackgroundProperty.GetValue(); }
          set { _slideshowBackgroundProperty.SetValue(value); }
        }
    public AbstractProperty SlideshowBackgroundProperty
        {
          get { return _slideshowBackgroundProperty; }
        }
    public MPPhotoSlideshowModel()
        {
          try
          {
    _slideshowBackgroundProperty = new WProperty(typeof(object), null);
    settings = new XMLSettings(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\MPPhotoSlideshow\", "MPPhotoSlideshow2.xml");
            SlideshowBackground= settings.getXmlAttribute("BackgroundPath");
            _pictureList= new ObservableCollection<BindingPicture>();
            _pictureList.Add(new BindingPicture() { Left=10, Top=10, PictureImage=@"C:\Users\Mark\Pictures\Tulips.jpg"});
            PictureList.FireChange();
    }
    }
     

    morpheus_xx

    Retired Team Member
  • Team MediaPortal
  • March 24, 2007
    12,073
    7,459
    Home Country
    Germany Germany
    I created the ObservableCollection recently, but after doing so, I think it's not the best idea to use them. The problem is that it fires change notification after each change (add, remove), which is slow. So I hesitate to merge this branch, as it is not an optimal solution for MPF.

    Please use the ItemsList, its the MPF way for list bindings. Don't forget to call "ItemsList.FireChanged" once, after list has been rebuilt completely.

    Another thing: we are unfortunately missing the HeaderedItemsControl in MPF, so you might look for alternatives.

    I could use such a control also in other places, it would help a lot (i.e. TV guide) :(
     

    sccrgoalie1

    Portal Pro
    September 12, 2013
    109
    165
    38
    Home Country
    United States of America United States of America
    I created the ObservableCollection recently, but after doing so, I think it's not the best idea to use them. The problem is that it fires change notification after each change (add, remove), which is slow. So I hesitate to merge this branch, as it is not an optimal solution for MPF.

    Please use the ItemsList, its the MPF way for list bindings. Don't forget to call "ItemsList.FireChanged" once, after list has been rebuilt completely.
    Alright, I'll switch it up to an ItemList. Thanks.

    Another thing: we are unfortunately missing the HeaderedItemsControl in MPF, so you might look for alternatives.

    I could use such a control also in other places, it would help a lot (i.e. TV guide) :(

    I originally tried using an ItemsControl but that didn't exist in MPF, HeaderedItemsControl does seem to exist at least partially. It may not be fully implemented and that's a reason it's not working, but it is in the source.
     

    morpheus_xx

    Retired Team Member
  • Team MediaPortal
  • March 24, 2007
    12,073
    7,459
    Home Country
    Germany Germany
    HeaderedItemsControl does seem to exist at least partially. It may not be fully implemented and that's a reason it's not working, but it is in the source
    Oh, yes you are right. It is used for TreeView and TreeViewItem, so it should also work :)
     

    sccrgoalie1

    Portal Pro
    September 12, 2013
    109
    165
    38
    Home Country
    United States of America United States of America
    HeaderedItemsControl does seem to exist at least partially. It may not be fully implemented and that's a reason it's not working, but it is in the source
    Oh, yes you are right. It is used for TreeView and TreeViewItem, so it should also work :)
    Cool. I'll keep plugging at it with your advice above.
     

    Users who are viewing this thread

    Top Bottom