Windows Phone update/refresh binding - c#

I have a textblock in my listbox called "feedTitle" which I want to change the forground color of. I use Foreground="{Binding Converter={StaticResource NewsTextColorConverter}}" for the binding of the forground color. Now the strange problem is that, if I choose a color in the listpicker("Lys" or "Dark" value) it runs the IValueConverter Convert method, but it dont show the color in the GUI, only if I restart my whole app it shows the color I chosen. It's like it only set the color of the forground of the textblock once.
MainPage.xaml
<ListBox Grid.Row="1" Name="feedListBox" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectionChanged="feedListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Top">
<TextBlock TextDecorations="Underline" FontSize="24" Name="feedTitle" TextWrapping="Wrap" Margin="12,0,0,0" Foreground="{Binding Converter={StaticResource NewsTextColorConverter}}" Text="{Binding Title.Text, Converter={StaticResource RssTextTrimmer}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in my app file:
App.xaml
<Application.Resources>
<converter:NewsTextColorConverter xmlns:converter="clr-namespace:NordjyskeRss" x:Key="NewsTextColorConverter" />
</Application.Resources>
I use a listpicker where a user select the value "Mørk" or "Lys" and then I want the textblock forground color to update its forground color. I call the Convert method and pass null as arguments, it seems to run the method fine:
MainPage.cs
private void lpkThemes_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Make sure we don't handle the event during initiation.
if (e.RemovedItems != null && e.RemovedItems.Count > 0)
{
if (this.lpkThemes.SelectedItem != null)
{
settings[THEMES_SETTING_KEY] = lpkThemes.SelectedItem.ToString();
if (lpkThemes.SelectedItem.ToString() == "Mørk")
{
n.Convert(null, null, null, null);
}
else
{
n.Convert(null, null, null, null);
}
}
}
}
This is where I use a IValueConverter to check for what color to use on the textblock and then add it:
MainPage.cs
public class NewsTextColorConverter : IValueConverter
{
protected IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
protected const string THEMES_SETTING_KEY = "Themes";
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (settings.Contains(THEMES_SETTING_KEY))
{
string themesValue = (string)settings[THEMES_SETTING_KEY];
if (themesValue == "Mørk")
{
return new SolidColorBrush(Colors.Green);
}
else
{
return new SolidColorBrush(Colors.Blue);
}
}
return new SolidColorBrush(Colors.Green);
//throw new NotSupportedException("ColorToBurshConverter only supports converting from Color and String");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

I think you need to redesign your app in the following way:
Add the following line into your app.xaml or page resources: <SolidColorBrush x:Key="brushListItemsForeground" Color="#FFFFFFFF" />
Replace Foreground="{Binding Converter={StaticResource NewsTextColorConverter}}" with Foreground="{StaticResource brushListItemsForeground}"
In your SelectionChanged:
var brush = (SolidColorBrush)Application.Current.Resources["brushListItemsForeground"]; if you’ve added the brush to app.xaml, or = (SolidColorBrush)this.Resources["brushListItemsForeground"]; if you’ve added the brush to page resources. Then change the Color property of the brush based on your settings.
P.S. There’re also other correct ways: e.g. create a SettingsContainer class that implements INotifyPropertyChanged, add it into some resource dictionary <local:SettingsContainer x:Key="mySettings" />, then bind to its properties e.g. Foreground="{Binding listItemsForeground, Source={StaticResource mySettings}}", when you need to change the value, change the listItemsForeground property of your class and raise PropertyChanged.
Currently, you’re abusing value converter using then as value providers, they were not designed for that, and that is why you have issues updating those values.

Related

How can I detect my keyboard without press enter C# WPF

How can i change this code to active detecion of my keyboard. Now it is showing what i write after press enter. How can i show what i can write without enter key.
XAML:
<StackPanel>
<TextBlock Width="300" Height="20">
Type some text into the TextBox and press the Enter key.
</TextBlock>
<TextBox Width="300" Height="30" Name="textBox1"
KeyDown="OnKeyDownHandler"/>
<TextBlock Width="300" Height="100" Name="textBlock1"/>
</StackPanel>
C#:
private void OnKeyDownHandler(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)
{
textBlock1.Text = "You Entered: " + textBox1.Text;
}
}
Or maybe is some diffrent way to create it?
You could simply bind the text directly:
<StackPanel>
<TextBlock Width="300" Height="20">
Type some text into the TextBox and it will appear in the field automatically.
</TextBlock>
<TextBox Width="300" Height="30" Name="textBox1" />
<TextBlock Width="300" Height="100" Name="textBlock1" Text="{Binding Text, ElementName=textbox1}"/>
</StackPanel>
This way you don't need any code-behind.
EDIT
If you want more sophisticated stuff, try this. Implement a new class in your project like this:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return $"You entered: {value ?? "nothing"}";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
and then change your binding to
<Window.Resources>
<local:MyConverter x:Key="MyConverter"/>
</Window.Resources>
<StackPanel>
<TextBox Name="txtEdit" />
<TextBlock Text="{Binding Text, Converter={StaticResource MyConverter}, ElementName=txtEdit}" />
</StackPanel>
Don't forget the resources for the window.
Here is a screen video showing it in action:
textBlock1.Text = "You Entered: " + **textBox1.Text**;
Don't use direct control property, in contrast use MVVM and binding.
"The UpdateSourceTrigger property of a binding controls how and when a changed value is sent back to the source."
http://www.wpf-tutorial.com/data-binding/the-update-source-trigger-property/
If I correctly understood the question, you need tunneling PreviewKeyDown event:
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.G)
{
e.Handled = true;
}
}
Alternatively, you can you use Keyboard class. In fact, Keyboard class can be used anywhere in your code:
private void SomeMethod()
{
if (Keyboard.IsKeyDown(Key.LeftCtrl))
{
MessageBox.Show("Release left Ctrl button");
return;
}
//Do other work
}

How to modify Image Source in WPF XAML dynamically

I have a WPF App that has (so far) 2 modes of display, regularmode and widgetmode.
I am using Prism 6 with MVVM design pattern.
MainWindowViewModel knows the mode of display.
ToolBarView has, as expected, a toolbar of buttons and the buttons shall be dynamically changed to different images depending on the mode of the view. If the mode is WidgetMode, it switches to the image with an identical name but with an '_w' added. So instead of "image.png", it's "image_w.png".
What I'd like to do is create a string in ToolBarView that is updated to either String.Empty or to "_w", depending on the mode. I'd also like the image root folder to be a global string, rather than a hardcoded string, so I have defined that in app.xaml.
<Application.Resources>
<sys:String x:Key="ImageURIRoot">/MyApp;component/media/images/</sys:String>
</Application.Resources>
Then in my toolbarview (a usercontrol), I did this:
<UserControl.Resources>
<converters:StringToSourceConverter x:Key="strToSrcConvert"/>
<sys:String x:Key="BtnImgSuffix">_w</sys:String>
.
.
.
</UserControl.Resources>
Note that the string is hardcoded; eventually, I will change it dynamically based off the windowmode.
I then put the Buttons in a Listbox
<ListBoxItem Style="{StaticResource MainButton_Container}">
<Button Command="{Binding ButtonActionDelegateCommand}" Style="{StaticResource Main_Button}">
<Image Source="{Binding Source={StaticResource ImageURIRoot}, Converter={StaticResource strToSrcConvert}, ConverterParameter='{}{0}button.png'}" />
</Button>
</ListBoxItem>
Converter code:
public class StringToSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter is string)
{
return string.Format(parameter.ToString(), value);
}
return null;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
So that works. But what I want is to have the ConverterParameter equal "{}{0}button{1}.png", where {0} is the URI Root and {1} is the suffix. But I can't figure out how to do it. I know it's simple, but I can't put my finger on it!
Please help!
Figured it out and it was through multibinding. The way I did it was create a converter that inherits from IMultiValueConverter. Its "Convert" method looks like this:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
ImageSourceConverter conv = new ImageSourceConverter();
int suffixPos = ((String)parameter).Length - 4;
var returnValue = ((String)parameter).Insert(suffixPos, values[1].ToString());
returnValue = Path.Combine(values[0].ToString(), returnValue);
ImageSource imgsrc = conv.ConvertFromString(returnValue) as ImageSource;
return imgsrc;
}
The xaml looks like this:
<Image Height="30" Width="40" diag:PresentationTraceSources.TraceLevel="High">
<Image.Source>
<MultiBinding Converter="{StaticResource stringsToSrcConvert}" ConverterParameter="buttonImg.png">
<Binding Source="{StaticResource ImageURIRoot}"/>
<Binding Source="{StaticResource BtnImgSuffix}"/>
</MultiBinding>
</Image.Source>
</Image>
Also, had to modify the URIRoot
<Application.Resources>
<sys:String x:Key="ImageURIRoot">pack://application:,,,/MyApp;component/media/images/</sys:String>
</Application.Resources>
Thanks, Clemens!

How to make IValueConverter return text with different fontsizes, superscripts and/or subscripts

Can anyone please let me know how I could make a Converter return text with varying font-sizes, so that the bound textblock can display it? If this is not possible with a TextBlock, I can use alternative element as well.
Here is the code that I have right now, this obviously doesn't work
In my XAML file:
<TextBlock Text="{Binding Converter={StaticResource LabelFormatConerter}}"/>
In my XAML.cs file:
public class LabelFormatConerter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TextBlock tb = new TextBlock();
Run runLargeFont = new Run();
runLargeFont.FontSize = 18;
runLargeFont.Text = "Larger Font Text";
tb.Inlines.Add(runBase);
Run runSmallFont = new Run();
runSmallFont.FontSize = 8;
runSmallFont.BaselineAlignment = BaselineAlignment.Superscript;
runSmallFont.Text = "Smaller Font Text";
tb.Inlines.Add(runSmallFont);
return tb.Text;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
This should work for you:
<TextBlock FontFamily="Calibri">
<Run>Normal Text</Run>
<Run Typography.Variants="Superscript">Test</Run>
<Run Typography.Variants="Subscript">7</Run>
</TextBlock>
Not all fonts support super\subscripts, so I had to specify it explictly.
What will be your input? Two/three separate values, or one value that you need to split into a normal value, superscript and subscript?
This might be possible to do with a TextBlock but I don't know how. Your converter returns a collection of Run objects, while the Text property expects a string.
An alternative is to user an items control:
<ItemsControl ItemsSource="{Binding Converter={StaticResource LabelFormatConerter}}" />
and return
tb.Inlines
from your converter. (ideally you just create just a collection inside your converter, not a new TextBlock)
A converter is not the right tool for this job - this is what ContentTemplate is there for. Simply use a ContentControl, bind the data to the Content property and display the data however your want to in your ContentTemplate:
<ContentControl Content="{Binding Person}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock>
<Run FontSize="18" Text="{Binding FirstName}" />
<Run FontSize="8" Text="{Binding LastName}" />
</TextBlock>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>

How can I access properties of an item in a StackPanel in C#?

<ListBox x:Name="noteListBox"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" Foreground="#FF329BD6" Margin="0,24,0,85">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="noteTitle"
FontSize="40"
Text="{Binding Titolo}"
Tag="{Binding FileName}"
Foreground="#FF45B1EE" Tap="apriNota" Margin="5,0,0,0" />
<TextBlock x:Name="noteDateCreated"
Text="{Binding DateCreated}"
Margin="10,0,0,10" Foreground="#FF60ADD8" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I need to dynamically change the Foreground color of those two TextBlocks inside the StackPanel. The problem is that they don't seem to be accessible from my C# code, suppose because they're in that StackPanel.
So basically this is what I need to do:
noteTitle.Foreground = new SolidColorBrush(Color.FromArgb(255, 50, 155, 214));
But I can't even find noteTitle in my C# code... How can I fix this?
Thank you!
I would suggest using value converter for such purposes. I assume foreground value depends on a state of object whcih ahs proeprties FileName, DateCreated you bind to, so just use this object as converetr parameter and in converter do main calculation to decide which Foreground should be returned for this particular item.
public class EntityToForegroundConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var entity = value as IMyEntity;
// TODO: determine a foreground value based on bound
// object proerrty values
}
public object ConvertBack(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
return null;
}
}
<Control.Resources>
<src:EntityToForegroundConverter x:Key="foregroundConverter"/>
</Control.Resources>
<TextBlock
Foreground="{Binding Converter={StaticResource foregroundConverter}}" />
if you want get element you can use this code:
var a = noteListBox.ItemTemplate.LoadContent() as StackPanel;
(a as StackPanel).Background = Brushes.Red;
foreach (UIElement child in a.Children)
{
if (child is TextBlock)
if ((child as TextBlock).Name.CompareTo("noteDateCreated") == 0)
{
(child as TextBlock).Foreground = Brushes.Red;
}
}
or you want change change Template ,you can create Template by code,and overWrite Template:
DataTemplate template = new DataTemplate(typeof(Test));
FrameworkElementFactory spOuterFactory =new FrameworkElementFactory(typeof(StackPanel));
FrameworkElementFactory block1 = new FrameworkElementFactory(typeof(TextBlock));
FrameworkElementFactory block2 = new FrameworkElementFactory(typeof(TextBlock));
block1.SetValue(TextBlock.ForegroundProperty, Brushes.Red);
Binding binding1 = new Binding();
binding1.Path = new PropertyPath("Titolo");
block1.SetBinding(TextBlock.TextProperty, binding1);
block2.SetValue(TextBlock.ForegroundProperty, Brushes.Red);
Binding binding2 = new Binding();
binding2.Path = new PropertyPath("noteDateCreated");
block2.SetBinding(TextBlock.TextProperty, binding2);
spOuterFactory.AppendChild(block1);
spOuterFactory.AppendChild(block2);
template.VisualTree = spOuterFactory;
noteListBox.ItemTemplate = template;

Dynamic custom content in RichTextBox

I wish to display a text + hyperlinks in a RichTextBox from the code-behind or the binded via the Xaml if there is the possibility.
For the moment, I have a string variable with a Url (that I'd like very much to make clickable) binded to a TextBlock. I'd like to basically replace:
<TextBlock Text="{Binding myTextWithUrl}" />
by (in a richTB: )
<Run Text="partOfTextNonUrl" /><Hyperlink NavigateUri="theUrl" TargetName="whatever" />
Here is how it is presented:
I have an ItemsControl templated with a custom object
<ItemsControl ItemsSource="{Binding FeedResults}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" >
<my:SearchResultItem />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And this custom control presents the binded data in 3 TextBlocks as presented above: title, date, and the text containing text + urls.
I have already a method that extracts the urls from the string, I just don't know how to use it. I can generate dynamically Run() and Hyperlink(), and add them to the paragraph, but how to bind ?
Or any other solution ? You'd make my day!!
Thanks, Sylvain
OK. So apparently inline Hyperlinks aren't even allowed in Silverlight. But you can make your own!
http://csharperimage.jeremylikness.com/2009/11/inline-hyperlinks-in-silverlight-3.html
Not easy - at least not as easy at it should be. But it should get the job done.
Once you have the ability to add these runs with hyperlinks, the way I'd approach it is this. Create a user control with a single TextBlock (txtContent). Set the DataContext="{Binding myTextWithUrl}". Then in the code behind:
public TextWithUrlUserControl()
{
InitializeComponent();
this.Loaded += (s, e) =>
{
foreach(var inline in ParseText(DataContext as string))
txtContent.Inlines.Add(inline);
};
}
IEnumerable<Inline> ParseText(string text)
{
// return list of Runs and Runs with hyperlinks using your URL parsing
// for demo purposes, just hardcoding it here:
return new List<Inline>
{
new Run{Text="This text has a "},
new Run{Text="URL", RunExtender.NavigateUrl="http://www.google.com/"},
new Run{Text="in it!"}
};
}
Hope this is helpful.
I would do something like this. Create a ValueConverter which will take your text (with the URL in it). Then in your TextBlock, create the Run and Hyperlink - bind both to the text, both using the ValueConverter, but with a different parameter to the ValueConverter.
The ValueConverter:
public class MyCustomValueConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(parameter.ToString()== "URL")
{
// return the URL part of the string
}
else
{
// return the non-URL portion of the string
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then your XAML looks like this:
<Run Text="{Binding myTextWithUrl, Converter={StaticResource valueConverter}}"></Run><Hyperlink NavigateUri="{Binding myTextWithUrl, Converter={StaticResource valueConverter}, ConverterParameter=URL}"></Hyperlink>

Categories

Resources