WPF Update Listbox Databinding - c#

I'm new to WPF and am working on Databinding a Listbox from a xml file, everything loads correctly when the program starts, however I'm having trouble making the listbox update after I insert a new record. Everything that I've read is pointing to use a ObservableCollection which I am, but I can't figure out how to get the Listbox to refresh. I have tried calling a update to the ItemsSource but it still doesn't seem to work. Ideally I would like to just have a Refresh button that A user can click to update the listbox. Does anyone have any suggestions on a calling a update to the list box
Thanks Michael
public class ContactList
{
string contactFile = #"U:\Peridot\Users\" + Program.getUser.ToString() + ".xml";
public ContactList()
{
}
public ContactList(string contactFullName, string contactCellNumber,string contactBusinessNumber, string contactExtension, string contactEmail, string contactStatus,string contactAuralinkStatus, string contactAuralinkID)
{
this.ContactFullName = contactFullName;
this.ContactCellNumber = contactCellNumber;
this.ContactBusinessNumber = contactBusinessNumber;
this.ContactExtension = contactExtension;
this.ContactEmail = contactEmail;
this.ContactStatus = contactStatus;
this.ContactAuralinkStatus = contactAuralinkStatus;
this.ContactAuralinkID = contactAuralinkID;
}
private string ContactFullName;
public string PropContactFullName
{
get { return ContactFullName; }
set { ContactFullName = value; }
}
private string ContactCellNumber;
public string PropContactCellNumber
{
get { return ContactCellNumber; }
set { ContactCellNumber = value; }
}
private string ContactBusinessNumber;
public string PropContactBusinessNumber
{
get { return ContactBusinessNumber; }
set { ContactBusinessNumber = value; }
}
private string ContactEmail;
public string PropContactEmail
{
get { return ContactEmail; }
set { ContactEmail = value; }
}
private string ContactStatus;
public string PropContactStatus
{
get { return ContactStatus; }
set { ContactStatus = value; }
}
private string ContactAuralinkStatus;
public string PropContactAuralinkStatus
{
get { return ContactAuralinkStatus; }
set { ContactAuralinkStatus = value; }
}
public string ContactAuralinkID;
public string PropContactAuralinkID
{
get { return ContactAuralinkID; }
set { ContactAuralinkID = value; }
}
private string ContactExtension;
public string PropContactExtension
{
get { return ContactExtension; }
set { ContactExtension = value; }
}
}
public class Contacts : System.Collections.ObjectModel.ObservableCollection<ContactList>
{
string contactFile = #"U:\Peridot\Users\" + Program.getUser.ToString() + ".xml";
//Added this
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
{
CollectionChanged(this, e);
}
}
public Contacts(): base()
{
getContactFile();
XDocument doc = XDocument.Load(contactFile);
var contacts = from r in doc.Descendants("Contact")
select new
{
FullName = r.Element("FullName").Value,
CellNumber = r.Element("CellNumber").Value,
BusinessNumber = r.Element("BusinessNumber").Value,
Extension = r.Element("Extension").Value,
Email = r.Element("Email").Value,
AuralinkID = r.Element("AuralinkID").Value
};
foreach (var r in contacts)
{
Add(new ContactList(r.FullName,r.CellNumber , r.BusinessNumber,r.Extension, r.Email, "", "",r.AuralinkID));
}
}
private void getContactFile()
{
if (!File.Exists(contactFile))
{
new XDocument(
new XElement("Contacts"
)
)
.Save(contactFile);
}
}
}
private void addContactICON_MouseDown(object sender, MouseButtonEventArgs e)
{
if (!doesContactExist())
{
try
{
XDocument doc = XDocument.Load(#"U:\Peridot\Users\" + Program.getUser.ToString() + ".xml");
XElement contact = new XElement("Contact");
contact.Add(new XElement("ContactID", contactID.ToString()));
contact.Add(new XElement("FullName", contactNameLBL.Content.ToString()));
contact.Add(new XElement("CellNumber", c1.Content.ToString()));
contact.Add(new XElement("BusinessNumber", businessPhoneIcon.ToolTip.ToString()));
contact.Add(new XElement("Extension", c3.Content.ToString()));
contact.Add(new XElement("Email", emailIcon.ToolTip.ToString()));
contact.Add(new XElement("AuralinkID", videoIcon.ToolTip.ToString()));
doc.Element("Contacts").Add(contact);
doc.Save(#"U:\Peridot\Users\" + Program.getUser.ToString() + ".xml");
MessageBox.Show(contactNameLBL.Content.ToString() + " has been added to your contacts.");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
else
MessageBox.Show("Contact Already Exists");
}
XAML
<StackPanel>
<StackPanel.Resources>
<local:Contacts x:Key="contactListobj"></local:Contacts>
</StackPanel.Resources>
<ListBox x:Name="contactList" Width="305" Margin="5,3,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" ItemsSource="{Binding Source={StaticResource contactListobj}}" Height="450" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
<TextBlock Text="{Binding PropContactFullName}" ToolTip="{Binding PropContactFullName}" Height="35" Width="175" FontSize="12"/>
<TextBlock x:Name="contactEmailLBL" Text="{Binding PropContactEmail}" ToolTip="{Binding PropContactEmail}" Cursor="Hand" Width="30" Height="35" MouseLeftButtonUp="contactEmailLBL_MouseLeftButtonUp" Foreground="{x:Null}" FontSize="1">
<TextBlock.Background>
<ImageBrush Stretch="Uniform" ImageSource="Images/emailICON.png"/>
</TextBlock.Background>
</TextBlock>
<TextBlock x:Name="cellNumberLBL" Text="{Binding PropContactCellNumber}" ToolTip="{Binding PropContactCellNumber}" Cursor="Hand" MouseLeftButtonUp="cellNumberLBL_MouseLeftButtonUp" Width="30" Height="35" Foreground="{x:Null}" FontSize="1">
<TextBlock.Background>
<ImageBrush Stretch="Uniform" ImageSource="Images/mobilePhoneICON.png"/>
</TextBlock.Background>
</TextBlock>
<TextBlock x:Name="businessNumberLBL" Text="{Binding PropContactBusinessNumber}" ToolTip="{Binding PropContactBusinessNumber}" Cursor="Hand" Width="30" Height="35" MouseLeftButtonUp="businessNumberLBL_MouseLeftButtonUp" Foreground="{x:Null}" FontSize="1">
<TextBlock.Background>
<ImageBrush Stretch="Uniform" ImageSource="Images/BusinessPhoneICON.png"/>
</TextBlock.Background>
</TextBlock>
<TextBlock x:Name="auralinkLBL" Text="{Binding PropContactAuralinkID}" ToolTip="{Binding PropContactAuralinkID}" Cursor="Hand" Width="30" Height="35" Foreground="{x:Null}" FontSize="1" MouseLeftButtonUp="auralinkLBL_MouseLeftButtonUp">
<TextBlock.Background>
<ImageBrush Stretch="Uniform" ImageSource="Images/VideoICON.png"/>
</TextBlock.Background>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>

From what I can tell based on the source code for ObservableCollection, the problem is most likely that the Add method you are using to add ContactList objects to your ObservableCollection is part of the Collection class that ObservableCollection inherits from. This does not fire the CollectionChanged event on the ObservableCollection so your binding is never notified that the collection has changed. Try calling the OnCollectionChanged protected method after you add each item to the collection.

Related

Binding WPF with Caliburns only works for some of the properties

For some reason my bindings in my program doesn't work for all my properties.
View
<StackPanel
Grid.Row="0"
Orientation="Horizontal" Margin="0,0,0,5" Grid.ColumnSpan="2">
<TextBlock
Margin="10"
VerticalAlignment="Center"
Text="Camera device: "
Foreground="White"/>
<ComboBox
Name="CameraDevices"
ItemsSource="{Binding ConnectedDevices}" <!-- This binds fine -->
SelectedItem="{Binding SelectedCamera}" <!-- This binds fine -->
Width="168"
VerticalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" /> <!-- This binds fine -->
</StackPanel>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<TextBlock Grid.Row="2" Grid.Column="1" x:Name="SelectedCamera_Name" Foreground="White"/> <!-- This binds fine -->
<StackPanel
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal" Width="100" Margin="58,0,59,0">
<Button
x:Name="ToggleButton"
Width="80"
Margin="10"
Height="25"
Content="Start" <!-- This binds to the function Start in my viewmodel (not shown)-->
/>
</StackPanel>
<Border
x:Name="devicecamContainer"
Grid.Column="0"
Grid.Row="3"
BorderBrush="Black"
BorderThickness="0">
<Image Source="{Binding Path=CameraImage, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" /> <!-- DOES NOT WORK -->
</Border>
</Grid>
ViewModel
public class UIViewModel : Screen
{
#region Properties
public BindableCollection<CameraModel> ConnectedDevices { get; set; }
private CameraModel _selectedCamera;
public CameraModel SelectedCamera
{
get { return _selectedCamera; }
set
{
_selectedCamera = value;
NotifyOfPropertyChange(() => SelectedCamera);
}
}
private ImageSource _cameraImage;
public ImageSource CameraImage
{
get { return _cameraImage; }
set { _cameraImage = value;
System.Diagnostics.Debug.WriteLine("Updated " + _cameraImage);
NotifyOfPropertyChange(() => CameraImage);
}
}
public UIViewModel()
{
ConnectedDevices = new BindableCollection<CameraModel>(CameraDevicesEnumerator.GetAllConnectedCameras());
}
public async void ToggleButton() //It's the same button for start/stop
{
if (_started == false)
{
_started = true;
var selectedCameraDeviceId = SelectedCamera.OpenCvId;
if ((_camera == null || _camera.CameraDeviceId != selectedCameraDeviceId))
{
_camera?.Dispose();
_camera = new CameraStreaming(cameraDeviceId: SelectedCamera.OpenCvId);
}
try
{
await _camera.StartCamera(true);
await _ultraSound.StartCamera(false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
LoadingVisibility = false;
}
else
{
_started = false; // To be implemented
}
}
(Both have been edited down a bit, to only show relevant info)
The CameraImage is set in a helperclass, but It's set to the correct value, and updated as expected. But for some reason it doesn't show in my view.
I've tried binding it in a few different ways:
<Image Source="{Binding=CameraImage" />
<Image Source="{Binding=CameraImage, UpdateSourceTrigger=PropertyChanged}" />
<Image Source="{Binding Path=CameraImage}" />
<Image Source="{Binding Path=CameraImage, UpdateSourceTrigger=PropertyChanged}" />
<Image x:Name="CameraImage" />
CameraStreaming - *Helper class*
public sealed class CameraStreaming : IDisposable
{
private System.Drawing.Bitmap _lastFrame;
private Task _previewTask;
UIViewModel viewModel = new UIViewModel();
private CancellationTokenSource _cancellationTokenSource;
public int CameraDeviceId { get; private set; }
public CameraStreaming(int cameraDeviceId)
{
CameraDeviceId = cameraDeviceId;
}
public async Task StartCamera(bool crop)
{
if (_previewTask != null && !_previewTask.IsCompleted)
return;
var initializationSemaphore = new SemaphoreSlim(0, 1);
_cancellationTokenSource = new CancellationTokenSource();
_previewTask = Task.Run(async () =>
{
try
{
var videoCapture = new VideoCapture();
if (!videoCapture.Open(CameraDeviceId))
{
throw new ApplicationException("Cannot connect to camera");
}
using (var frame = new Mat())
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
videoCapture.Read(frame);
if (!frame.Empty())
{
if (initializationSemaphore != null)
initializationSemaphore.Release();
_lastFrame = BitmapConverter.ToBitmap(frame);
var lastFrameBitmapSource = _lastFrame.ToBitmapSource();
lastFrameBitmapSource.Freeze();
viewModel.CameraImage = lastFrameBitmapSource;
}
await Task.Delay(10);
}
}
videoCapture?.Dispose();
}
finally
{
if (initializationSemaphore != null)
initializationSemaphore.Release();
}
}, _cancellationTokenSource.Token);
await initializationSemaphore.WaitAsync();
initializationSemaphore.Dispose();
initializationSemaphore = null;
if (_previewTask.IsFaulted)
{
// To let the exceptions exit
await _previewTask;
}
}
EDIT! Posted my CameraStreaming-class
None of them works. My other bindings, which are in the same ViewModel works just fine.
What am I doing wrong?

Template10 UI not refreshing after property changed

I'm working on a UWP App using the Template 10, and I don't manage to get the UI updated after a property is changed in the ViewModel. I tried to implement the Bindable base at the Model, but still doesn't work.
XAML:
<Page.DataContext>
<vm:RoomPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<Grid x:Name="RoomProperties"
RelativePanel.Below="pageHeader"
RelativePanel.AlignLeftWithPanel="True">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Image Grid.Column="0" Width="220" Height="220" Stretch="Fill" Source="{x:Bind ViewModel.Room.Image}"></Image>
<TextBlock Grid.Column="1" FontSize="16" Text="{x:Bind ViewModel.Room.Name}"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1" FontSize="16" Text="Room Type: "></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="1" FontSize="16" Text="{x:Bind ViewModel.Room.Type}"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="2" FontSize="16" Text="Room Number: "></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="2" FontSize="16" Text="{x:Bind ViewModel.Room.Number}"></TextBlock>
</Grid>
<ListView x:Name="SensorListView"
ItemsSource="{x:Bind ViewModel.Room.Sensors}"
IsEnabled="False"
RelativePanel.Below="RoomProperties"
RelativePanel.AlignLeftWithPanel="True">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:Sensor">
<StackPanel HorizontalAlignment="Left">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="16" Text="{x:Bind Name}"></TextBlock>
<TextBlock Grid.Column="1" FontSize="16" Text="{x:Bind SensorValues[0].Value, Mode=TwoWay}"></TextBlock>
<TextBlock Grid.Column="2" FontSize="16" Text="{x:Bind Units}"></TextBlock>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel:
public class RoomPageViewModel : ViewModelBase
{
Template10.Services.SerializationService.ISerializationService _SerializationService;
private FileIOHelper.FileIOHelper fileIOHelper = new FileIOHelper.FileIOHelper();
private AppServiceConnection serialCommandService;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
public RoomPageViewModel()
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
Room = Room.CreateNewRoom();
}
}
private Room room = Room.CreateNewRoom();
public Room Room
{
get
{
return this.room;
}
set
{
Set(ref room, value);
}
}
public void UpdateRoom()
{
foreach (var sensor in Room.Sensors)
{
var sensorValue = new SensorValue();
sensorValue.Sensor = "R" + Room.Number + "D" + sensor.DeviceNumber + "S" + sensor.Type;
ObservableCollection<SensorValue> newList = fileIOHelper.ReadFromFile(sensorValue).ToObservableCollection();
SensorValue newSensorValue = newList.Last();
sensor.SensorValues = new ObservableCollection<SensorValue> { newSensorValue };
}
foreach (var actuator in Room.Actuators)
{
var actuatorValue = ActuatorValue.CreateNewActuatorValue();
actuatorValue.Actuator = "R" + Room.Number + "D" + actuator.DeviceNumber + "A" + actuator.Type;
ObservableCollection<ActuatorValue> newList = fileIOHelper.ReadFromFile(actuatorValue).ToObservableCollection();
ActuatorValue newActuatorValue = newList.Last();
actuator.ActuatorValues = new ObservableCollection<ActuatorValue> { newActuatorValue };
}
}
public async void RefreshButton_Click(object sender, object parameter)
{
Random rnd = new Random();
Room = Room.CreateNewRoom(rnd.Next(1, 9));
//UpdateRoom();
await Task.CompletedTask;
}
Model:
public class Room : BindableBase
{
private string name;
private string image;
private string type;
private int number;
public string Name
{
get
{
return name;
}
set
{
Set(ref name, value);
}
}
public string Image
{
get
{
return image;
}
set
{
Set(ref image, value);
}
}
public string Type
{
get
{
return type;
}
set
{
Set(ref type, value);
}
}
public int Number
{
get
{
return number;
}
set
{
Set(ref number, value);
}
}
private ObservableCollection<Sensor> sensors;
private ObservableCollection<Actuator> actuators;
public ObservableCollection<Sensor> Sensors
{
get
{
return sensors;
}
set
{
Set(ref sensors, value);
}
}
public ObservableCollection<Actuator> Actuators
{
get
{
return actuators;
}
set
{
Set(ref actuators, value);
}
}
public Room() {
Random rnd = new Random();
Name = "DefaultName";
Image = "DefaultImage";
Type = "DefaultType";
Number = rnd.Next(1,9);
Sensors = new ObservableCollection<Sensor>();
Actuators = new ObservableCollection<Actuator>();
}
public Room(int inputNumber)
{
Name = "DefaultName";
Image = "DefaultImage";
Type = "DefaultType";
Number = inputNumber;
Sensors = new ObservableCollection<Sensor>();
Actuators = new ObservableCollection<Actuator>();
}
public static Room CreateNewRoom(int inputNumber)
{
return new Room(inputNumber);
}
}
I used this guide for documentation for the implementation (https://github.com/Windows-XAML/Template10/wiki/MVVM). Any idea on why the UI is not getting updated? Thanks.
A mistake most people (including myself) often make when being used to the 'old' Binding syntax is that x:Bind has OneTime binding as default instead of OneWay binding.
Mode: Specifies the binding mode, as one of these strings: "OneTime", "OneWay", or "TwoWay". The default is "OneTime". Note that this differs from the default for {Binding}, which is "OneWay" in most cases.
Source: MSDN
What you need for your binding updates to work is:
Using INotifyPropertyChanged, this is handled by BindableBase.
Set the correct mode, e.g.
Text="{x:Bind ViewModel.Room.Number, Mode=OneWay}

LongListSelector ItemsSource not working

In my Windows Phone 8.1 store app I am having trouble to show values in LongListSelector. Here is .xaml and .cs files.
Am I missing something?
<controls:LongListSelector Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch"
DataContext="{Binding ElementName=PageWorld}"
ItemsSource="{Binding Countries}" RenderTransformOrigin="0.5,0.5" BorderBrush="Blue" BorderThickness="2">
<controls:LongListSelector.RenderTransform>
<CompositeTransform/>
</controls:LongListSelector.RenderTransform>
<controls:LongListSelector.ItemTemplate>
<DataTemplate>
<ListBoxItem Margin="0,6,0,6">
<StackPanel>
<TextBlock Text="{Binding Title}" TextWrapping="NoWrap" Foreground="Black"/>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</controls:LongListSelector.ItemTemplate>
</controls:LongListSelector>
In code behing I am binding values as follows.
private ObservableCollection<Country> _countries;
public ObservableCollection<Country> Countries
{
get { return _countries; }
set
{
_countries = value;
OnPropertyChanged();
}
}
public World()
{
InitializeComponent();
navigationHelper = new NavigationHelper(this);
navigationHelper.LoadState += this.NavigationHelper_LoadState;
navigationHelper.SaveState += this.NavigationHelper_SaveState;
Countries = GetCountries();
}
public class Country
{
public string Title { get; set; }
}
private ObservableCollection<Country> GetCountries()
{
ObservableCollection<Country> countries = new ObservableCollection<Country>();
for (int i = 0; i < 100; i++)
{
Country country = new Country();
country.Title = "Name" + i;
countries.Add(country);
}
return countries;
}

Collection not binding to treeview

I have an Observablecollection with type of EntityBase. EntityBase is a base class for Ticket,Project,... classes. Now I want to bind that collection to treeview but when debugging there is no data showing. Also there is no binding error at output debug window.
There is the codes:
public partial class ReminderExtendedWindow : Window , INotifyPropertyChanged
{
private ObservableCollection<EntityBase> coll;
public ObservableCollection<EntityBase> Coll
{
get
{ if (coll == null) coll = new ObservableCollection<EntityBase>(); return coll; }
set { coll = value; NotifiyPropertyChanged("Coll"); }
}
public ReminderExtendedWindow()
{
InitializeComponent();
this.ResizeMode = ResizeMode.NoResize;
Ticket ticket = new Ticket();
ticket.TicketId = 3535;
ticket.TicketUrl = "http://www.google.com";
ticket.TicketRequestTypeName = "denemeticket";
Project project = new Project();
project.ProjectUrl = "http://www.google.com";
project.ProjectId = 1221;
project.ProjectTypeName = "denemeproj";
Coll.Add(ticket);
Coll.Add(project);
}
}
The XAML file codes:
<TreeView Height="500" Width="375" Background="Transparent" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,50,0,0"
BorderThickness="0,0,0,0" x:Name="EntityTree" ItemsSource="{Binding Coll}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type BusinessLayerEntity:Ticket}" ItemsSource="{Binding}">
<TextBlock>
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding TicketUrl}">
<TextBlock Text="{Binding TicketId}"></TextBlock>
</Hyperlink>
<TextBlock Text="{Binding TicketRequestTypeName}"></TextBlock>
</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type BusinessLayerEntity:Project}" ItemsSource="{Binding}">
<TextBlock>
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding ProjectUrl}">
<TextBlock Text="{Binding ProjectId}" ></TextBlock>
</Hyperlink>
<TextBlock Text="{Binding ProjectTypeName}"></TextBlock>
</TextBlock>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Here is classes: (Ticket class also have the same properties)
public class Project : EntityBase, IEntityBase
{
private string projectUrl;
private string projectTypeName;
private int projectId;
public string ProjectUrl { get { return projectUrl; } set { projectUrl = value; } }
public string ProjectTypeName { get { return projectTypeName; } set { projectTypeName = value; } }
public int ProjectId { get { return projectId; } set { projectId = value; } }
}
Any help will be greatly appreciated :) Thanks
Try adding DataContext = this; to the end of your ReminderExtendedWindow constructor

Two-way binding on a ContentControl

I'm creating a Key/Value pair editor and would like for the value to have a custom template based on the data type.
<TextBox x:Uid="txtKey" x:Name="txtKey" Grid.Column="1" Grid.Row="0" Text="{Binding ElementName=This, Path=KeyValuePair.Key}" VerticalAlignment="Top"/>
<ContentControl Grid.Column="1" Grid.Row="1"
x:Uid="ContentControl1" x:Name="ContentControl1"
Content="{Binding ElementName=This, Path=KeyValuePair.Value}"
LostFocus="ContentControl1_LostFocus"
DataContextChanged="ContentControl1_DataContextChanged" />
The codebehind for the host class looks like this:
public partial class KeyValueControl : ControlBase
{
private System.Collections.DictionaryEntry _dictionaryEntry;
private KeyValuePairObjectObject _KeyValuePair = new KeyValuePairObjectObject();
private DataTemplate _editorDataTemplate;
private Caelum.Libraries.Ui.Editors.Resources resources = new Editors.Resources();
public DataTemplate EditorDataTemplate
{
get { return _editorDataTemplate; }
set { _editorDataTemplate = value; SendPropertyChanged("EditorDataTemplate"); }
}
public KeyValuePairObjectObject KeyValuePair
{
get { return _KeyValuePair; }
set { _KeyValuePair = value; SendPropertyChanged("KeyValuePair"); }
}
public KeyValueControl()
{
InitializeComponent();
this.DataUpdated += new DataUpdatedHander(KeyValueControl_DataUpdated);
DataContextChanged += new DependencyPropertyChangedEventHandler(KeyValueControl_DataContextChanged);
}
void KeyValueControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
}
public override void Save()
{
base.Save();
}
void KeyValueControl_DataUpdated(object sender, object data)
{
if (Data != null)
{
_dictionaryEntry = (System.Collections.DictionaryEntry)Data;
KeyValuePair.Key = _dictionaryEntry.Key;
KeyValuePair.Value = _dictionaryEntry.Value;
if (KeyValuePair.Value != null)
{
EditorDataTemplate = resources.GetDataTemplate(_dictionaryEntry.Value.GetType());
ContentControl1.ContentTemplate = EditorDataTemplate;
}
}
}
}
DataTemplates are chosen via the resources class:
public DataTemplate GetDataTemplate(Type type)
{
if (type == typeof(string))
{
return TextInlineEditorTemplate;
}
if (type == typeof(bool))
{
return BooleanInlineEditorTemplate;
}
return null;
}
The DataTemplate that is displayed for a string is:
<DataTemplate x:Uid="TextInlineEditorTemplate" x:Key="TextInlineEditorTemplate" >
<Grid>
<TextBox x:Uid="txtTextIET1" x:Name="txtTextIET1" Width="300" Text="{Binding Path=DataContext, Mode=TwoWay, RelativeSource={RelativeSource Self}, BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
The data binds OK to the key TextBox (txtKey) and DataTemplate TextBox (txtTextIET1), but changing the value on txtTextIET1 will not trigger the setter on the KeyValuePair property. I've not been able to find any examples of this scenario, so any help would be appreciated.
Didn't this work for you
<DataTemplate x:Uid="TextInlineEditorTemplate" x:Key="TextInlineEditorTemplate" >
<Grid>
<TextBox x:Uid="txtTextIET1" x:Name="txtTextIET1" Width="300" Text="{Binding}" />
</Grid>
</DataTemplate>

Categories

Resources