Conditional data validation in wpf - wpf

I have 3 radio buttons and a text box.
See the image for UI
When user selects 'Phone' radio button I should allow to enter only numbers in the textbox, similarly the other cases email and name.
Email should be in correct format. and name should start with character.
How to do this in wpf?

Please try the next:
The TextBox code
<TextBox x:Name="TextBoxWithValidation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding Text, UpdateSourceTrigger=LostFocus, Mode=TwoWay,
NotifyOnValidationError=True, ValidatesOnDataErrors=True}">
<Validation.ErrorTemplate>
<ControlTemplate>
<DockPanel>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder x:Name="ControlWithError"/>
</Border>
<ContentControl x:Name="ValidationSymbol" Margin="-10,0,0,0" Content="{Binding ElementName=ControlWithError,
Path=AdornedElement.(Validation.Errors), Converter={wpfValidationIssueHelpAttempt:Errors2ValidationErrorContentConverter},
UpdateSourceTrigger=PropertyChanged}" ContentTemplate="{StaticResource CommonValidationSymbol}"/>
</DockPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
The converter code:
public class Errors2ValidationErrorContentConverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var errors = value as ReadOnlyCollection<ValidationError>;
ValidationError error;
if (errors == null || (error = errors.FirstOrDefault()) == null) return null;
return error.ErrorContent.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The validation symbol code(put this to the resource section):
<DataTemplate x:Key="CommonValidationSymbol">
<TextBlock Panel.ZIndex="1000" Foreground="Red" FontFamily="Segoe UI" FontWeight="Bold"
Width="10"
FontSize="15" Background="#0000FF00" Text="!">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" Content="{Binding }" Placement="Right"/>
</ToolTipService.ToolTip>
</TextBlock>
</DataTemplate>
Here is my DataContext code
public class MainViewModel:BaseObservableObject, IDataErrorInfo
{
private string _text;
private string _error;
private bool _isMailChecked;
private bool _isNameChecked;
private bool _isPhoneChecked;
public virtual string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged(() => Text);
}
}
public string this[string columnName]
{
get
{
if (columnName == "Text")
{
if (string.IsNullOrEmpty(Text)) return string.Empty;
Error = string.Empty;
return GetValidationResult();
}
return String.Empty;
}
}
private string GetValidationResult()
{
//define your logic here
if (IsNameChecked)
{
Error = "name is wrong!";
}
if (IsMailChecked)
{
Error = "mail is wrong!";
}
if (IsPhoneChecked)
{
Error = "phone is wrong";
}
return Error;
}
public string Error
{
get { return _error; }
private set
{
_error = value;
OnPropertyChanged(() => Error);
}
}
public bool IsNameChecked
{
get { return _isNameChecked; }
set
{
_isNameChecked = value;
OnPropertyChanged(() => IsNameChecked);
if (value == false) return;
IsMailChecked = false;
IsPhoneChecked = false;
Text = String.Empty;
}
}
public bool IsMailChecked
{
get { return _isMailChecked; }
set
{
_isMailChecked = value;
OnPropertyChanged(() => IsMailChecked);
if (value == false) return;
IsNameChecked = false;
IsPhoneChecked = false;
Text = String.Empty;
}
}
public bool IsPhoneChecked
{
get { return _isPhoneChecked; }
set
{
_isPhoneChecked = value;
OnPropertyChanged(() => IsPhoneChecked);
if (value == false) return;
IsMailChecked = false;
IsNameChecked = false;
Text = String.Empty;
}
}
}
Regards.

Related

WPF - How to change content of ContentControl clicking on TreeViewItem?

I am working on a WPF project and I am facing a problem. I have searched for 2 days a solution but I have never found anything that could help me...
I have a TreeView with different data types inside and a ContentControl that shows views corresponding to these different data types. I want, when I click on a TreeViewItem that, depending on the data type contained in this TreeViewItem, it changes the view in the ContentControl.
I reached to execute different commands depending on the TreeviewItem selected but it never changes the view...
Does somebody have an answer or an idea that could help me ?
I use this for my TreeView :
<TreeView x:Name="networkTree" ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="490" TreeViewItem.Selected="GetHeaderSelectedItem"/>
It executes this :
public class NetworkConfigViewModel : BindableBase
{
private IRegionManager regionManager;
private bool _showRDConf;
private bool _showNetworkConf;
private bool _showDeviceInfo;
public NetworkConfigViewModel(IRegionManager regionManager)
{
this.regionManager = regionManager;
regionManager.RegisterViewWithRegion("NetworkConfigInfoRegion", typeof(NetworkConfigInfoView));
regionManager.RegisterViewWithRegion("RDConfigurationRegion", typeof(RDConfigurationView));
regionManager.RegisterViewWithRegion("DeviceInfoRegion", typeof(DeviceInfoView));
ShowNetworkConfCommand = new DelegateCommand(NetworkConf);
ShowRDConfCommand = new DelegateCommand(RDConf);
ShowDeviceInfoCommand = new DelegateCommand(DevInfo);
_showNetworkConf = true;
_showRDConf = false;
_showDeviceInfo = false;
}
public bool ShowRDConf
{
get
{
return _showRDConf;
}
set
{
SetProperty(ref _showRDConf, value);
}
}
public bool ShowNetworkConf
{
get
{
return _showNetworkConf;
}
set
{
SetProperty(ref _showNetworkConf, value);
}
}
public bool ShowDeviceInfo
{
get
{
return _showDeviceInfo;
}
set
{
SetProperty(ref _showDeviceInfo, value);
}
}
public DelegateCommand ShowNetworkConfCommand { get; set; }
public DelegateCommand ShowRDConfCommand { get; set; }
public DelegateCommand ShowDeviceInfoCommand { get; set; }
private void NetworkConf()
{
ShowRDConf = false;
ShowDeviceInfo = false;
ShowNetworkConf = true;
System.Windows.Forms.MessageBox.Show("Commande ShowNetConf executée :\nShowNetworkConf="+ShowNetworkConf.ToString()+"\nShowRDConf="+ShowRDConf.ToString() + "\nShowDeviceInfo=" + ShowDeviceInfo.ToString());
}
private void RDConf()
{
ShowNetworkConf = false;
ShowDeviceInfo = false;
ShowRDConf = true;
System.Windows.Forms.MessageBox.Show("Commande ShowRConf executée :\nShowRDConf="+ShowRDConf.ToString()+"\nShowNetworkConf="+ShowNetworkConf.ToString() + "\nShowRDeviceInfo=" + ShowDeviceInfo.ToString());
}
private void DevInfo()
{
ShowNetworkConf = false;
ShowRDConf = false;
ShowDeviceInfo = true;
System.Windows.Forms.MessageBox.Show("Commande ShowDeviceInfo executée :\nShowDeviceInfo=" + ShowDeviceInfo.ToString() + "\nShowNetworkConf=" + ShowNetworkConf.ToString() + "\nShowRDConf=" + ShowRDConf.ToString());
}
public void ChangeNetworkView(TreeView tree)
{
TreeViewItem tvi = null;
tvi = tree.SelectedItem as TreeViewItem;
if (tvi != null)
{
if (tvi.Tag.ToString() == "Network")
{
ShowNetworkConfCommand.Execute();
}
else if(tvi.Tag.ToString()=="RD")
{
ShowRDConfCommand.Execute();
}
else if (tvi.Tag.ToString() == "VD")
{
ShowDeviceInfoCommand.Execute();
}
}
}
}
And for my ContentControl :
<ContentControl x:Name="RDView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowRDConf, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="RDConfigurationRegion"/>
<ContentControl x:Name="NetworkView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowNetworkConf, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="NetworkConfigInfoRegion"/>
<ContentControl x:Name="DeviceView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowDeviceInfo, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="DeviceInfoRegionq"/>
Thank you by advance

How to show and hide image in Item List control in Windows Phone

I have a list control and each item contains two images and text. On the click on each item I want to hide or show selected image on selected list item.
Here is XAML code snippet:
<ListBox x:Name="list" SelectionChanged="list_SelectionChanged" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding ImagePath}" Stretch="None"/>
<Image Source="{Binding ImagePath}" Stretch="None"
Visibility="{Binding ImageVisibility,
Converter={StaticResource boolVisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C# code:
dataSource = new ObservableCollection<ImageData>()
{
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = false},
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = true},
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = true},
new ImageData(){Name = "User2:", ImagePath="/Images/user2.png", ImageVisibility = true}
};
List Selection Changed Event:
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
((ImageData)(((object[])(e.AddedItems))[0])).ImageVisibility = false;
list.UpdateLayout();
}
ImageData class:
public class ImageData
{
public string ImagePath { get; set; }
public string Name { get; set; }
public bool ImageVisibility { get; set; }
}
Image Visibility Converter:
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
bool? nullable = (bool?)value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
}
}
Please help me to accomplish such functionality.
You need to use INotifyPropertyChanged interface http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
For example so:
public class ImageData : INotifyPropertyChanged
{
private bool _imageVisibility;
public string ImagePath { get; set; }
public string Name { get; set; }
public bool ImageVisibility
{
get
{
return _imageVisibility;
}
set
{
_imageVisibility = value;
OnPropertyChanged("ImageVisibility");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Full changes according to your task you can see here (dropbox)

Update ObservableCollecttion on objects property changed

Hopefully someone can help me out with this. I am creating a Silverlight app which is used for editing images. A user has a project which contain layers which contain elements. (Elements are text and image elements).
I have a class which represents the project. It contains an ObservableCollection and each Layer has an ObservableCollection. Element is an abstract class. There is a TextElement and ImageElement class which inherit from Element.
My problem is the UI never gets updated when I change an element inside the collection. I am using INotifyPropertyChanged on all my properties and I am catching CollectionChanged on the collections but still no go. The CollectionChanged event for ObservableCollection never gets hit on an update of one of its elements.
This is the code I had originally had:
void Elements_CollectionChanged(
object sender,
System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{ this.NotifyChange("Elements"); }
This is the binding:
<!-- Workspace -->
<ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="5" DataContext="{Binding Project}">
<Canvas x:Name="Canvas" Background="LightGray" Width="{Binding Path=CanvasWidth}" Height="{Binding Path=CanvasHeight}">
<ItemsControl ItemsSource="{Binding Path=Layers, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Elements, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="{Binding Path=BackgroundColor}"
Visibility="{Binding Path=Visible, Converter={StaticResource BoolConverter}}"
Opacity="{Binding Path=Opacity}"
Width="{Binding ElementName=Canvas, Path=DataContext.CanvasWidth}"
Height="{Binding ElementName=Canvas, Path=DataContext.CanvasHeight}">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<ContentControl Content="{Binding Converter={StaticResource ElementConverter}}"
Canvas.Top="{Binding Path=Top, Mode=TwoWay}"
Canvas.Left="{Binding Path=Left, Mode=TwoWay}"
Opacity="{Binding Path=Opacity}"
MouseLeftButtonDown="ContentControl_MouseLeftButtonDown">
<interactivity:Interaction.Behaviors>
<behaviors:DragInCanvasBehavior />
</interactivity:Interaction.Behaviors>
</ContentControl>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</ScrollViewer>
This is my converter:
public class LayerElementToFrameworkElementConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Element element = value as Element;
if (element is ImageEditor.Client.BLL.TextElement)
{
ImageEditor.Client.BLL.TextElement txt = element as ImageEditor.Client.BLL.TextElement;
return CreateTextBlock(txt);
}
else if (element is ImageElement)
{
ImageElement imgEle = element as ImageElement;
return CreateImage(imgEle);
}
else
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
FrameworkElement frameworkElement = value as FrameworkElement;
if (frameworkElement is TextBlock)
{
TextBlock txtBlock = value as TextBlock;
return CreateTextElement(txtBlock);
}
else if (frameworkElement is Image)
{
Image img = value as Image;
return CreateImageElement(img);
}
else
return null;
}
private TextBlock CreateTextBlock(TextElement textElement)
{
TextBlock text = new TextBlock();
text.Text = textElement.Text;
text.Cursor = Cursors.Hand;
text.SetValue(Canvas.ZIndexProperty, textElement.Order);
ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
SolidColorBrush brush = (SolidColorBrush)converter.Convert(textElement.Color, null, null, null);
text.Foreground = brush;
return text;
}
private TextElement CreateTextElement(TextBlock textBlock)
{
TextElement textElement = new TextElement();
textElement.Text = textBlock.Text;
textElement.Top = (double)textBlock.GetValue(Canvas.TopProperty);
textElement.Left = (double)textBlock.GetValue(Canvas.LeftProperty);
textElement.Order = (int)textBlock.GetValue(Canvas.ZIndexProperty);
ColorHexToBrushConverter converter = new ColorHexToBrushConverter();
textElement.Color = (string)converter.ConvertBack(textBlock.Foreground, null, null, null);
return textElement;
}
private Image CreateImage(ImageElement imageElement)
{
Image img = new Image();
img.Width = imageElement.Width;
img.Height = imageElement.Height;
img.Source = imageElement.Source;
img.Opacity = imageElement.Opacity;
img.Cursor = Cursors.Hand;
img.SetValue(Canvas.ZIndexProperty, imageElement.Order);
img.SetValue(Canvas.TopProperty, imageElement.Top);
img.SetValue(Canvas.LeftProperty, imageElement.Left);
return img;
}
private ImageElement CreateImageElement(Image image)
{
ImageElement imageElement = new ImageElement();
imageElement.Width = image.Width;
imageElement.Height = image.Height;
imageElement.Source = (BitmapImage)image.Source;
imageElement.Order = (int)image.GetValue(Canvas.ZIndexProperty);
return imageElement;
}
}
This is the class which contains to collection:
public class Layer : BaseBLL
{
private int numberOfElements;
#region Properties
public int Order
{
get { return this.GetValue<int>("Order"); }
set { this.SetValue<int>("Order", value); }
}
public string BackgroundColor
{
get { return this.GetValue<string>("BackgroundColor"); }
set { this.SetValue<string>("BackgroundColor", value); }
}
public double Opacity
{
get { return this.GetValue<double>("Opacity"); }
set { this.SetValue<double>("Opacity", value); }
}
public bool Visible
{
get { return this.GetValue<bool>("Visible"); }
set { this.SetValue<bool>("Visible", value); }
}
public ObservableCollection<Element> Elements { get; set; }
public Element SelectedElement
{
get { return this.GetValue<Element>("SelectedElement"); }
set { this.SetValue<Element>("SelectedElement", value); }
}
#endregion
#region Commands
public ICommand AddTextElementCommand { get; set; }
public ICommand AddImageElementCommand { get; set; }
public ICommand DeleteElementCommand { get; set; }
public ICommand SetSelectedElementCommand { get; set; }
#endregion
#region Methods
public Layer()
:this("Untitled", 0, "#ffffff", 1, true, new ObservableCollection<Element>())
{
}
public Layer(string name, int order, string backgroundColor, double opacity, bool visible, ObservableCollection<Element> elements)
: base(name)
{
this.Order = order;
this.BackgroundColor = backgroundColor;
this.Opacity = opacity;
this.Visible = visible;
this.Elements = elements;
this.Elements.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Elements_CollectionChanged);
this.AddTextElementCommand = new DelegateCommand(AddTextElement, CanAddTextElement);
this.AddImageElementCommand = new DelegateCommand(AddImageElement, CanAddImageElement);
this.DeleteElementCommand = new DelegateCommand(DeleteElement, CanDeleteElement);
}
private void Elements_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (Element element in e.NewItems)
element.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(element_PropertyChanged);
}
void element_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.NotifyChange("Elements");
}
private bool CanAddTextElement(object param) { return true; }
private void AddTextElement(object param)
{
TextElement text = new TextElement();
text.Order = this.numberOfElements;
this.Elements.Add(text);
numberOfElements++;
this.SelectedElement = text;
}
private bool CanAddImageElement(object param) { return true; }
private void AddImageElement(object param)
{
var dialog = new OpenFileDialog()
{
Filter = "Image Files (*.bmp;*.jpg;*.gif;*.png;)|*.bmp;*.jpg;*.gif;*.png;",
Multiselect = false
};
bool? userClickedOK = dialog.ShowDialog();
if (userClickedOK == true)
{
string fileName = dialog.File.Name;
FileStream stream = dialog.File.OpenRead();
var imageSource = new BitmapImage();
using (FileStream fileStream = stream)
{
imageSource.SetSource(fileStream);
byte[] data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
fileStream.Flush();
fileStream.Close();
}
ImageElement img = new ImageElement();
img.Name = fileName;
img.Order = this.numberOfElements;
img.Source = imageSource;
img.Height = imageSource.PixelHeight;
img.Width = imageSource.PixelWidth;
this.Elements.Add(img);
this.numberOfElements++;
this.SelectedElement = img;
}
}
private bool CanDeleteElement(object param)
{
if (this.SelectedElement != null)
return true;
else
return false;
}
private void DeleteElement(object param)
{
throw new NotImplementedException();
}
#endregion
}
This is the code for the one of the Elements:
public class TextElement : Element
{
public string Text
{
get { return this.GetValue<string>("Text"); }
set { this.SetValue<string>("Text", value); }
}
public int FontSize
{
get { return this.GetValue<int>("FontSize"); }
set { this.SetValue<int>("FontSize", value); }
}
public bool Bold
{
get { return this.GetValue<bool>("Bold"); }
set { this.SetValue<bool>("Bold", value); }
}
public bool Italic
{
get { return this.GetValue<bool>("Italic"); }
set { this.SetValue<bool>("Italic", value); }
}
public string Color
{
get { return this.GetValue<string>("Color"); }
set { this.SetValue<string>("Color", value); }
}
public FontFamily Font
{
get { return this.GetValue<FontFamily>("Font"); }
set { this.SetValue<FontFamily>("Font", value); }
}
public TextElement()
: this("Untitled", 1, 5, 5, 0, 0, 0, "New text", 12, false, false, "#aaaaaa", new FontFamily("Arial"))
{
}
public TextElement(string name, double opacity, double top, double left, double rotateAngle, double centerX, double centerY,
string text, int fontSize, bool bold, bool italic, string color, FontFamily font)
: base(name, opacity, top, left, rotateAngle, centerX, centerY)
{
this.Text = text;
this.FontSize = fontSize;
this.Bold = bold;
this.Italic = italic;
this.Color = color;
this.Font = font;
}
}
If anyone can help I would be very grateful.
Do you fire the PropertyChanged event from inside SetValue?
Otherwise, you should do it for each property of Element.
public string Text
{
get { return this.GetValue<string>("Text"); }
set { this.SetValue<string>("Text", value); this.InvokePropertyChanged("Text"); }
}
private void InvokePropertyChanged( string propertyName )
{
if( this.PropertyChanged != null )
this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}

Listbox binding

Hello I have problem with binding data to Listbox. In shortway... I want list all my Skydrive files.
My XAML
<TextBlock Height="35" HorizontalAlignment="Left" Margin="9,6,0,0" Name="infoTextBlock" Text="" VerticalAlignment="Top" Width="Auto" />
<my:SignInButton Name="signInButton1" ClientId="<correct ClientId>" Scopes="wl.signin wl.basic wl.skydrive" Branding="Windows" TextType="SignIn" SessionChanged="signInButton1_SessionChanged" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="198,-6,0,0" />
<StackPanel Height="578" HorizontalAlignment="Left" Margin="10,50,0,0" Name="StackContentPanel" VerticalAlignment="Top" Width="440">
<ListBox Height="465" Name="FileList" Width="380" ItemsSource="{Binding Files}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
My class and cs.
namespace EReader.ViewModel
{
public class File
{
public File()
{}
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
}
}
public class FilesManager
{
public ObservableCollection<string> Files;
public FilesManager()
{
Files = new ObservableCollection<string>();
}
}
namespace EReader
{
public partial class MainPage : PhoneApplicationPage
{
private LiveConnectClient client;
// Constructor
public MainPage()
{
InitializeComponent();
}
private void signInButton1_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
{
if (e.Status == LiveConnectSessionStatus.Connected)
{
client = new LiveConnectClient(e.Session);
infoTextBlock.Text = "Signed in.";
client.GetCompleted +=
new EventHandler<LiveOperationCompletedEventArgs>(OnGetCompleted);
client.GetAsync("/me/skydrive/files/");
}
else
{
infoTextBlock.Text = "Not signed in.";
client = null;
}
}
void OnGetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
//Gdy uda nam się podłaczyc do konta skydrive
if (e.Error == null)
{
signInButton1.Visibility = System.Windows.Visibility.Collapsed;
#region Nazwa użytkownika
string firstName = "";
string lastName = "";
if (e.Result.ContainsKey("first_name") ||
e.Result.ContainsKey("last_name"))
{
if (e.Result.ContainsKey("first_name"))
{
if (e.Result["first_name"] != null)
{
firstName = e.Result["first_name"].ToString();
}
}
if (e.Result.ContainsKey("last_name"))
{
if (e.Result["last_name"] != null)
{
lastName = e.Result["last_name"].ToString();
}
}
infoTextBlock.Text =
"Hello, " + firstName +" "+ lastName + "!";
}
else
{
infoTextBlock.Text = "Hello, signed-in user!";
}
#endregion
#region Wszyskite pliki
List<object> data = (List<object>)e.Result["data"];
FilesManager fileManager = new FilesManager();
foreach (IDictionary<string,object> items in data)
{
File file = new File();
file.Name= items["name"].ToString();
fileManager.Files.Add(file.Name);
}
FileList.ItemsSource = fileManager.Files;
#endregion
}
else
{
infoTextBlock.Text = "Error calling API: " +
e.Error.ToString();
}
}
}
Files must be a property, not a field.
Furthermore {Binding Name} must be {Binding} instead, because a string has no Name property.
This has to be a public property:
public ObservableCollection<string> Files;
should be
public ObservableCollection<string> Files {get;set;}
Then your binding will work

How to force a refresh of the binding when bound to the entire object within a Template

I have a List of 'Rule' classes that is the source of a DataGrid. In this example I have one of the columns which is a DataGridTemplateColumn that is bound to the 'Verified' dependency property.
The problem I am having is that I have a VerifyColorConverter where I wish to pass in the ENTIRE 'Rule' object of the selected row so I can examine the Rule instance and return an appropriate brush. I do this in when setting the background of the Border (see code below - Background="{Binding Converter={StaticResource convVerify}}")
<DataGridTemplateColumn Header="Verified" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource convVerify}}"
CornerRadius="4" Height="17" Margin="2,0,2,0" VerticalAlignment="Center" >
<Grid>
<TextBlock Foreground="Yellow" Text="{Binding Path=Verified, Mode=OneWay}" TextAlignment="Center" VerticalAlignment="Center"
FontSize="11" FontWeight="Bold" />
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
This all works well when I set the source on the DataGrid but when the underlying 'Rule' object is altered the converter is not called upon so the brush stays the same. How can I force this to be updated when I alter some of the properties of the 'Rule' instance?
Any help appreciated!
Converter looks roughly like this:
[ValueConversion(typeof(CRule), typeof(SolidColorBrush))]
public class VerifyColorConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
CRule rule = value as CRule;
Color clr = Colors.Red;
int count = 0;
int verified = 0;
if (rule != null)
{
count = rule.TotalCount;
verified = rule.NoOfVerified;
}
if (count == 0) clr = Colors.Transparent;
else if (verified == 0) clr = (Color)ColorConverter.ConvertFromString("#FFD12626");
else if (verified < count) clr = (Color)ColorConverter.ConvertFromString("#FF905132");
else clr = (Color)ColorConverter.ConvertFromString("#FF568D3F");
SolidColorBrush brush = new SolidColorBrush(clr);
return brush;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
EDIT
This is part of Rule class:
/// <summary>
/// Compliance Restriction (Rule)
/// </summary>
public class Rule : BindElement
{
public CMode Mode { get; private set; }
public int RuleID { get; private set; }
public string RuleDescription { get; private set; }
private int _NoOfVerified = 0;
private int _TotalCount = 0;
public int NoOfVerified
{
get { return _NoOfVerified; }
set { _NoOfVerified = value; RaiseChanged("Progress"); RaiseChanged("Verified"); }
}
public int TotalCount
{
get { return _TotalCount; }
set { _TotalCount = value; RaiseChanged("Progress"); RaiseChanged("Verified"); }
}
public string Verified
{
get
{
if (TotalCount == 0) return "Nothing to verify";
return string.Format("Verified {0} out of {1}", NoOfVerified, TotalCount);
}
}
You could try using a MultiValueConverter instead of a regular Converter, and pass it whatever Rule Properties you need, or you can raise a CollectionChanged event when a property on the Rule gets changed. I usually prefer not to do this since I don't know how this affects performance, but it's an option.
Using a MultiConverter
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
Color clr = Colors.Red;
int count = 0;
int verified = 0;
if (values.Count >= 2
&& int.TryParse(count, values[0].ToString())
&& int.TryParse(verfieid, values[1].ToString()))
{
if (count == 0) clr = Colors.Transparent;
else if (verified == 0) clr = (Color)ColorConverter.ConvertFromString("#FFD12626");
else if (verified < count) clr = (Color)ColorConverter.ConvertFromString("#FF905132");
else clr = (Color)ColorConverter.ConvertFromString("#FF568D3F");
}
SolidColorBrush brush = new SolidColorBrush(clr);
return brush;
}
XAML for MultiConverter:
<Border.Background>
<MultiBinding Converter="{StaticResource convVerify}">
<Binding Value="{Binding TotalCount}" />
<Binding Value="{Binding NoOfVerified}" />
</MultiBinding>
</Border.Background>
Using Property Change Events
RulesCollection.CollectionChanged += RulesCollection_Changed;
void RulesCollection_Changed(object sender, CollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach(Rule rule in e.NewItems) // May need a cast here
rule.PropertyChanged += Rule_PropertyChanged;
if (e.OldItems != null)
foreach(Rule rule in e.OldItems) // May need a cast here
rule.PropertyChanged -= Rule_PropertyChanged;
}
void Rule_PropertyChanged()
{
RaisePropertyChanged("RulesCollection");
}
OK - I found a way around this - what I have done is expose the object as a property and then call the OnPropertyChanged for this property whenever anything changes. This is picked up properly by the Bind object and handed over to the Converter whenever a property changes!!
[Serializable()]
public class BindElement : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public void RaiseChanged(string s)
{
OnPropertyChanged(new PropertyChangedEventArgs(s));
}
#endregion
}
public class BindElement2 : BindElement
{
public void RaiseChanged(string s)
{
base.RaiseChanged(s);
NudgeMyself();
}
public void NudgeMyself()
{
base.RaiseChanged("Myself");
}
}
/// <summary>
/// Compliance Restriction (Rule)
/// </summary>
public class CRule : BindElement2
{
public CMode Mode { get; private set; }
public int RuleID { get; private set; }
public string RuleDescription { get; private set; }
private int _NoOfVerified = 0;
private int _TotalCount = 0;
public int NoOfVerified
{
get { return _NoOfVerified; }
set { _NoOfVerified = value; RaiseChanged("Progress"); RaiseChanged("Verified"); }
}
public int TotalCount
{
get { return _TotalCount; }
set { _TotalCount = value; RaiseChanged("Progress"); RaiseChanged("Verified"); }
}
public string Verified
{
get
{
if (TotalCount == 0) return "Nothing to verify";
return string.Format("Verified {0} out of {1}", NoOfVerified, TotalCount);
}
}
public CRule Myself
{
get { return this; }
}
and other classes can derived from BindElement2 and do the same: (create a property Myself that exposes the instance itself)
public class CTradeRule : BindElement2
{
public CRule Rule { get; set; }
public bool IsLocked { get; set; } // if true this should prevent a Reason from being given
public bool IsVerified { get { return Reason.Length > 0; } }
private string _Reason = ""; // ** no reason **
public string Reason
{
get { return _Reason; }
set { _Reason = value; RaiseChanged("Reason"); }
}
public int Progress
{
get { return (IsVerified ? 1 : 0); }
}
public override string ToString()
{
return string.Format("Rule: {0}, Reason: {1}", Rule.RuleID, _Reason);
}
public CTradeRule Myself
{
get { return this; }
}
}
Now in the xaml I can do this: (note the Binding Path=Myself) which then ensures the entire object is send to the converter WHENEVER any property changes!!
<DataGridTemplateColumn Header="Verified" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border Background="{Binding Path=Myself, Converter={StaticResource convVerify}}"
CornerRadius="4" Height="17" Margin="2,0,2,0" VerticalAlignment="Center" >
<Grid>
<TextBlock Foreground="Yellow" Text="{Binding Path=Verified, Mode=OneWay}" TextAlignment="Center" VerticalAlignment="Center"
FontSize="11" FontWeight="Bold" />
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Resources