Rebinding Image source while using a converter? - silverlight

I have a button with an image inside it. This button appears on a datagrid many times for displaying the status of the row. When the user clicks the button, it changes the state of the underlying object on the row to enabled or disabled. Here is what the button looks like:
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button CommandParameter="{Binding}" HorizontalAlignment="Center">
<Image Source="{Binding Converter={StaticResource EnableDisableConverter}}" Height="25" Width="25" />
</Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
The converter correctly returns the proper image based on the status. The problem is that I've switched to an MVVM model and my code for changing the image won't work anymore. My previous looked like this:
Image img = (Image)btn.Content;
if (c.Status == Administration.Web.ObjectStatus.Enabled) {
img.Source = new System.Windows.Media.Imaging.BitmapImage(new Uri("/Images/enable-icon.png", UriKind.Relative));
} else {
img.Source = new System.Windows.Media.Imaging.BitmapImage(new Uri("/Images/disable-icon.png", UriKind.Relative));
}
During the command that changes the status, I've tried raising a change to the property that contains the object, but it doesn't reflect it on the UI. If I do a hard refresh of the screen, the status correctly changes. Is there a way to have rebind the image in the current situation?

Bind the source of the image to some bool Enabled property and your EnableDisableConverter can than react to that value, after each change.
XAML:
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button CommandParameter="{Binding}" HorizontalAlignment="Center">
<Image Source="{Binding IsEnabled, Converter={StaticResource EnableDisableConverter}}" Height="25" Width="25" />
</Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
ViewModel:
...
public bool IsEnabled
{
get
{
return _isEnabled;
}
set
{
_isEnabled=value;
NotifyPropertyChanged("IsEnabled");
}
}
...
Converter:
public object Convert(object value, ...)
{
if((bool)value)
return uri of image1;
else
return uri of image2;
}
But I don't know what are the objects in the grid and what is the ViewModel. There may be a problem. The point is to have that IsEnabled property corectly binded to those objects in the grid.

Related

how to apply different font styles in one string

I have a wpf app, c# that displays texts (teahcer's name) when a combobox is closed. Basically it is contained in 1 string and being passed to the classInstance.TeachersComboBoxText or Text="{Binding Path=TeachersComboBoxText}" . Everything is great but the client is requesting for the text to be in italic if the teacher is flagged as not default or secondary teacher. Basically, I need to have a string but different font styles is applied to it,depends on my data.
<ComboBox Name="instanceTeachersComboBox"
IsEditable="True"
IsReadOnly="True"
ItemsSource="{Binding Path=TeacherList}" DropDownClosed="teachersComboBox_DropDownClosed"
Text="{Binding Path=TeachersComboBoxText}"
FontWeight="{Binding Path=IsSelectedFontWeight}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected}"
Background="{Binding Path=IsActiveColour}"
Content="{Binding Path=Display}"
Foreground="{Binding Path=IsClashColour}"
FontStyle="{Binding Path=EndDateFontStyle}"/>
<Image Source="/SchoolEdgeTimetable;component/Images/greentick16x16.png"
Margin="5,0,0,0"
Visibility="{Binding Path=IsSpecialitySubjectVisibility}"></Image>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
=== this is the code ====
if (classInstance.TeacherList.Any(c => c.IsSelected == true && c.IsDefault == false) || instanceCount != defaultCount)
{
System.Windows.Forms.RichTextBox rtf = new System.Windows.Forms.RichTextBox();
foreach (var item in data)
{
if (!item.IsDefault)
{
rtf.SelectionFont = new Font("Arial", 12, System.Drawing.FontStyle.Italic);
rtf.AppendText(item.Display);
}
text = GT.Join2Strings(text, item.IsDefault? item.Display : rtf.Text, "\n");
}
}
else
text = DEFAULT_TEXT;
classInstance.TeachersComboBoxText = text;
I tried rtf because it seems that I can't apply it in plain string, but the code is not working. Is there any way to solve this without using rtf? or if not why is my code not working? anyone ca suggest a better way to do this will be appreciated. thanks
UPDATE:
People are suggesting to modify the template which I already did, that is working great in showing the items when a combobox is open. One of my items is RED and in italic as you can see BUT What I am trying to do though is modify display of the combobox TEXT property. I have attached an image to get a better view on what I mean.
thanks
It's pretty simple if you know how to utilise <Run> tag of TextBlock control in code behind. See below code:
//loop through all the teachers
foreach (var teacher in vm.Teachers)
{
//check if teacher is default
if (teacher.IsDefault)
{
//add text to "tb" textblock, in italic style
tb.Inlines.Add(new Run(teacher.Name) { FontStyle = FontStyles.Italic });
}
else
{
//add text to "tb" textblock
tb.Inlines.Add(new Run(teacher.Name));
}
}
If you are keen to know more about inline formatting, here is a cool blog post for same. Let me know if you need any more help on this.
You could handle the Loaded event for the CheckBox in the ItemTemplate and set its Content property to a TextBlock of Inline elements, e.g.:
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected}"
Background="{Binding Path=IsActiveColour}"
Foreground="{Binding Path=IsClashColour}"
FontStyle="{Binding Path=EndDateFontStyle}"
Loaded="CheckBox_Loaded">
</CheckBox>
<Image Source="/SchoolEdgeTimetable;component/Images/greentick16x16.png"
Margin="5,0,0,0"
Visibility="{Binding Path=IsSpecialitySubjectVisibility}"></Image>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
private void CheckBox_Loaded(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
dynamic dataObject = checkBox.DataContext;
string display = dataObject.Display;
TextBlock textBlock = new TextBlock();
//split the display string and add Inlines to the TextBlock as suggested by #Naresh Ravlani here...
checkBox.Content = textBlock;
}
Add a datatrigger that changes your font to Italic:
<DataTrigger Binding="{Binding IsDefault}" Value="1">
<Setter Property="FontStyle" Value="Italic"/>
</DataTrigger>

WPF ListView item's Visible/Collaped not changing according to its Visibility

Thanks for your time reading my thread.
I am using VS2012, WFP, and .net4.5 on Windows 7 64bit
I have a ListView control with xaml in following:
<ListView Name="lvViewerControl"
SelectionMode="Single"
SelectedIndex="{Binding Path=ViewType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Background="{x:Null}"
BorderBrush="{x:Null}"
Margin="2">
<Label Name="lblView2D"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Image Source="/CaptureSetupModule;component/Icons/2D.png" />
</Label>
<Label Name="lblView3D"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Image Source="/CaptureSetupModule;component/Icons/3D.png" />
</Label>
<Label Name="lblViewTiles"
Width="40"
Height="40"
Margin="3"
Background="#FF595959"
Foreground="White"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Visibility="{Binding Path=XYCtrlVisible, Mode=TwoWay, Converter={StaticResource boolToVis}}">
<Image Source="/CaptureSetupModule;component/Icons/Tile.png" />
</Label>
</ListView>
Now I want to collapse the third item, lblViewTiles. I tried to combine its Visibility to a bool, then do the bool to visibility conversion, but it did not work. What I mean by not work is that the Visiblity only collapses when the application starts (the application loads the xml to get the Visibility as it starts). Afterwards, not matter how the binding variable (Visiblity) changes, and the value does change to Collapsed, but the lblViewTiles still in the ListView control, no UI change.
Here is how DataContext are binded:
The DataContex of the ListView is binded to CaptureSetupModules class. The ListView is defined in LiveVM class. The action which is the loading of the xml is in MasterView class. So in order to access the Visibility property in CaptureSetupModules, I simply created a CaptureSetupModules object in MasterView class,
In MasterView class
CaptureSetupModules _captureVM = new CaptureSetupModules();
...
LiveVM _liveVM = new LiveVM;
if (ndList.Count > 0)
{
xyBorder.Visibility = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? Visibility.Visible : Visibility.Collapsed;
tilesControlBorder.Visibility = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? Visibility.Visible : Visibility.Collapsed;
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
_captureVM.XYCtrlVisible = ndList[0].Attributes["Visibility"].Value.Equals("Visible") ? true:false;
}
)
);
}
And here is my converter:
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
var nullable = (bool?)value;
flag = nullable.GetValueOrDefault();
}
if (parameter != null)
{
if (bool.Parse((string)parameter))
{
flag = !flag;
}
}
if (flag)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
This code only makes the item collapsed the first time when the application starts , and it loads the visibility from the xml file. Afterwards, not matter how the XYCtrlVisible, the visibility binding, changes, the UI show no response. The item is always there, or not there.
Basically the problem is: the binded variable changes, the xml file changes as well, but the UI does not change, exception for the first time when the application launches as it loads the xml.
It is probably a little messy here, let me know if you need anything else. I am pretty confused myself too. Thanks.
On the property XYCtrlVisible you need to implement INotifyPropertyChanged
That is how the UI is notified of a changed
Why are you binding that two way?

Adding Dynamically Control in WPF on Button click

I have three Text Box called TxtDocumentTitle1, TxtDocumentTitle2,TxtDocumentTitle3 lastly there is a Add More Button. Client can Click Add more Button so that it generates Text box naming TxtDocumentTitle4. If more needed he/she can Add more Text Boxes.
Sample XAML code of View
<Grid Height="450" Width="700" Background="White">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,20,0,0" Name="textBlocKname" Text="Document Title1:" VerticalAlignment="Top" Width="110" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,87,0,0" Name="textBlockAddress" Text="Document Title2:" VerticalAlignment="Top" Width="110" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,154,0,0" Name="textBlockCompanyName" Text="Document Title3:" VerticalAlignment="Top" Width="110" />
<TextBox Height="46" Margin="67,37,87,0" Name="txtDocumentTitle1" VerticalAlignment="Top" FontSize="24" />
<TextBox Height="46" HorizontalAlignment="Left" Margin="67,106,0,0" Name="txtDocumentTitle3" VerticalAlignment="Top" Width="546" FontSize="24" />
<TextBox Height="46" HorizontalAlignment="Left" Margin="67,171,0,0" Name="txtDocumentTitle2" VerticalAlignment="Top" Width="546" FontSize="24" />
<Button Content="Add More" Height="37" HorizontalAlignment="Right" Margin="0,223,87,0" Name="btnAddmore" VerticalAlignment="Top" Width="102" />
</Grid>
You can achieve this easily via Binding. if your Window does not have a ViewModel open your window's xaml.cs and make it like this:
public Window1()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<TextBoxVm> Items { get { return _items; } }
private ObservableCollection<TextBoxVm> _items = new ObservableCollection<TextBoxVm>();
if not, just add the two last lines to the viewModel of your window.
Now you need to define a class derived from DependencyObject and name it say TextBoxVm. create two DependencyPropertys in it (use propdp snippet) as follows:
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextBoxVm), new UIPropertyMetadata("default text",
(d,e)=>
{
var vm = (TextBoxVm)d;
var val = (string)e.NewValue;
MyDataService.FindAndUpdateItemInDatabase(vm.Id, val);//you can access database with something like this
}));
public string TitleText
{
get { return (string)GetValue(TitleTextProperty); }
set { SetValue(TitleTextProperty, value); }
}
public static readonly DependencyProperty TitleTextProperty =
DependencyProperty.Register("TitleText", typeof(string), typeof(TextBoxVm), new UIPropertyMetadata("default title"));
This would be the xaml code:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding TitleText}"/>
<TextBox Text="{Binding Text}"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now the only thing left is to write Button logic. simply add TextBoxVm to Items when Button is clicked.
Items.Add(new TextBoxVm {
TitleText = string.Format("Document Title{0}:", Items.Count+1)
});
Edit Note:
this approach is standard MVVM (expect for the button click event, which should be done using Command). So if you want to add controls in code (which is not recommended) search this :
add control to wpf grid programmatically.
*Above Answer from Bizz Gives Solution of My Question * Beside that it Rise me a Question about *DependencyObject * after Few Research i found this about Dependancy Object which may be Helpful for New comer to WPF like me :)
What is DependencyObject??
Dependency object is the base object for all WPF objects. All the UI Elements like Buttons TextBox etc and the Content Elements like Paragraph, Italic, Span etc all are derived from Dependency Object.
Dependency objects are used for WPF property system. By default, what ever the property system we have in DOT Net CLR is very basic. But Dependency properies provide lots of addtional features/services to support Data Binding.
Once you create any property as a dependency property, then automatically you get following feature implemented for you. ie. Change Notification, Validation, Call Back, Inheritance, DataBinding, Styles, Default Values etc.
If you need to implement all these features on your own for all properties where you need these feature, then it will be a big process and head ache for you. So, these all coming out of the box from Dependency Object class.
Basically dependency object class contains a dictionary. So, when ever set any value or retrieve value, then it will change the value or read from that Dictionary. So, it is nothing but a key value pair.
For Detail Info abouT DependencyObject
http://www.codeproject.com/Articles/140620/WPF-Tutorial-Dependency-Property
http://www.pinfaq.com/32/what-is-dependency-object-in-wpf-where-should-i-use-it

Bind Image in DataTemplate to System.Drawing.Image

I am attempting to bind Image.Source in a DataTemplate to a System.Drawing.Image as discussed here: using XAML to bind to a System.Drawing.Image into a System.Windows.Image control
<UserControl.Resources>
<media:ImageConverter x:Key="imageConverter" />
<DataTemplate DataType="{x:Type data:GameTile}" >
<StackPanel Orientation="Vertical" Margin="5" Background="Transparent">
<Viewbox>
<TextBlock FontWeight="Bold" Text="{Binding PointValue}" TextAlignment="Center" FontSize="14" />
</Viewbox>
<Image Margin="0,5,0,0" Source="{Binding Path=Image.Image, Converter={StaticResource imageConverter}}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<loop:ListBox x:Name="listBox1"
ItemsSource="{Binding Path=GameModel.Game.GameTiles}"
ItemContainerStyle="{StaticResource GameTileContainerStyle}" Orientation="Vertical" />
</Grid>
The GameTile object has an Image (not a system.drawing.image) property that points to a Picture object which has an Image property of type System.Drawing.Image.
I am binding the ItemsSource on the ListBox to a GameTiles Collection on a Game object.
Objects
public class Game
{
public XPCollection<GameTile> GameTiles
{
get { return GetCollection<GameTile>("GameTiles"); }
}
}
public class GameTiles
{
Picture fImage;
public Picture Image
{
get { return fImage; }
set { SetPropertyValue<Picture>("Image", ref fImage, value); }
}
}
public class Picture
{
private FileData fFile;
public FileData File
{
get { return fFile; }
set
{
SetPropertyValue("File", ref fFile, value);
if (string.IsNullOrEmpty(fName))
{
fName = (value == null ? string.Empty : value.FileName);
}
fImage = null;
}
}
Image fImage;
public System.Drawing.Image Image
{
get
{
if (fImage == null)
{
try
{
MemoryStream stream = new MemoryStream();
fFile.SaveToStream(stream);
stream.Position = 0;
fImage = Image.FromStream(stream);
}
catch
{
//TODO: log exception
}
}
return fImage;
}
//set { SetPropertyValue<Image>("Image", ref fImage, value); }
}
}
The images are not showing up in the ListBoxItems, but any other property that I bind to in the DataTemplate will show up. It may be worth noting that I am using Devexpress Xpo as an ORM. Also the classes represented above do implement INotifyPropertyChanged.
Any thoughts on what I may be missing?
EDIT: Forgot to mention that I have implemented a value converter as mentioned in the post that I linked to above. However, if I put a breakpoint in the converter method, it is never called.
EDIT: Added the fFile property to the code above.
I can set an Image.Source to the GameTile.Image.Image property through c#(by converting it to BitmapImage), and have it work as expected, but I'm not sure how to accomplish that with a DataTemplate through c#. I would prefer to set the binding in XAML, but would settle for a c# workaround with a DataTemplate (or something else that would work). I am pretty confident that the issue is not with the GameTile.Image property pulling image from the database because if I manually set the source on an Image.Source in c#, the image is there. It simply isn't working in the DataTemplate.
Edit: Determined the issue to be related to properties that are not directly on the DataType that I am binding to for example with and GameTile has a (int)PointValue property, a (Picture object)Image property, and a (Prize object)Prize property.
If I bind to
<TextBlock Text="{Binding PointValue}" />
it works as expected.
But if I bind to
<TextBlock Text="{Binding Prize.Name}" />
it does not work.
And If I bind to
<Image Margin="0,5,0,0" Source="{Binding Image.BitmapImage}" />
it fails also. The following graphic shows the error that is being thrown by the binding.
BindingExpression path error: 'Name' property not found on 'object'
''XPCollection' (Hash=...)'. BindingExpression:Path=Prize.Name;
DataItem=GameTile' (HashCode=...); target element is
'TextBlock'(Name=''); target property is 'Text' (type 'String')
Thanks,
Eric
Found the solution.
Had to change this:
<TextBlock Text="{Binding Prize.Name}" />
to this:
<TextBlock Text="{Binding Prize!.Name}" />
The only difference is the exclamation point(!).
This also worked for the image property.
<Image Margin="0,5,0,0" Source="{Binding Path=Image!.Image, Converter={StaticResource imageConverter}}" />

How to select all checkbox inside telerik combox on checbox Checked event?

I have on checkbox inside telerik combo control. If User click on "All" option from checkbox list then I want select all checkboxs.
checkbox values.
My Sample code is below.
<telerik:RadComboBox Name="rcbDays" Grid.Row="1" Grid.Column="1" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding MonthDaysList}" VerticalAlignment="Center" >
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="chkDays" Content="{Binding DaysText}"
Tag="{Binding DaysValue}" Checked="chkDays_Checked" />
</StackPanel>
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
private void chkWeeks_Checked(object sender, RoutedEventArgs e)
{
//Here I want code for selecting all checkboxes.
}
The items that you bound the ComboBox to should have a property like IsSelected, then you should bind IsChecked of the data-template CheckBox to that. Then you just need to iterate over the source collection and set IsSelected=true on all items.
e.g.
public class MyClass : MyBaseClass // Whatever you may have called it,
{
public bool IsSelected { ... }
public string DaysText { ... }
//...
}
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DaysText}" Tag="{Binding DaysValue}" />
</StackPanel>
</DataTemplate>
//In the handler that is supposed to select all
foreach (var item in MonthDaysList) item.IsSelected = true;
Of course the property needs to have change notifications.
(Also a note on usability: I do not thing that ComboBoxes should contain CheckBoxes, if you need multiple item selection use a ListBox)
You need to take one more property isSelected as said by H.B.
add IsChecked="{Binding IsSelected}" to CheckBox tag in xaml file. Create one property in the appropriate class i.e. public bool isSeleted.......
When you get in to event chkWeeks_Checked() in this function get reference of the ComboBox item source like objList = (TypeCastYourClassType)YourComboBox.ItemSource;... Now the objList contains all checkbox items. Iterate through objList collection and get isSeleted property for each and every single item and that's done....
In your case
MonthDayList = (TypeCastYourClassType)rcbDays.ItemSource;
for(int i=0;i<MonthDayList.Count;i++)
{
MonthDayList[i].isSelected = true;
}
Here is some good discussion for allowing multiple values to be selected in the telerik combobox.
It uses checkbox within combobox
http://codedotnets.blogspot.in/2012/02/checkboxes-in-comboxes-to-allow.html
Thanks :)

Resources