Label Visibility.Collapsed on empty content WPF MVVM - c#

I'm trying to figure out how I can make hide a label when it's hidden & visible again when text is set using XAML. I can easily do it with a TextChanged event but there must be a correct way to do it using xaml, right?
I've done my research but I can't find anything that works.
Window1
<TextBox Name="nameTxt" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
Window2
<Label Name="nameLbl" Content="{Binding Name}" />

Basically it implements by built-in class in .Net BooleanToVisibilityConverter:
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="booleanVisibilityConverter"/>
</UserControl.Resources>
Let me show work example:
XAML:
<Button Content="Hello, I am the button" Visibility="{Binding ShowButton,
Converter={StaticResource booleanVisibilityConverter}}"/>
ViewModel:
private bool _showButton = false;
public bool ShowButton
{
get { return _showButton; }
set
{
if (value != _showButton)
{
_showButton = value;
OnPropertyChanged("ShowButton");
}
}
}
If you want to change the Visibility of your Button in code, you can make it by this code in ViewModel:
IsButtonVisible = false;

Add a custom converter.
wpf tutorial value converters
You can write the logic to test for string.IsNullOrEmpty and return hidden, otherwise return visible.
This approach is nice as it keeps visibility out of your view model.

Related

Binding TextBlock field to backend variable

First time really using WPF - thought I'd have a go at remaking something I did a while back in Java.
I'm trying to bind the Text value of a TextBlock on a popup to something that gets set in the backend, so I can use one handler method to display any message on said popup.
I've been trying multiple different routes, such as fully binding it in the cs instead of XAML like so:
<--XAML-->
<Popup Margin="89,75,0,0" Name="verif_popup" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="False" PopupAnimation="Slide" Placement="Center" Width="100" Height="100" Grid.Column="1">
<Popup.Effect>
<BlurEffect/>
</Popup.Effect>
<Canvas Background="Azure">
<TextBlock Name="VerifTextBlock"/>
</Canvas>
</Popup>
<--CS-->
private void SmallPopupHandler(string text)
{
Binding binding = new("Text")
{
Source = text
};
VerifTextBlock.SetBinding(TextBlock.TextProperty, binding);
verif_popup.IsOpen = true;
}
But it doesn't like the fact that the string isn't a TextBlock property, I sort of knew this wouldn't work but it seems the most logical to me having come from swing. There also doesn't seem to be a way for me to cast it to it and im not in the mood for making my own dependency property rn...
The next thing I tried was to bind the value to a field in the class, but I just got a stackoverflow error (haha nice)
<--XAML-->
<Popup Margin="89,75,0,0" Name="verif_popup" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="False" PopupAnimation="Slide" Placement="Center" Width="100" Height="100" Grid.Column="1">
<Popup.Effect>
<BlurEffect/>
</Popup.Effect>
<Canvas Background="Azure">
<Canvas.DataContext>
<local:MainWindow/>
</Canvas.DataContext>
<TextBlock Name="VerifTextBlock" Text="{Binding Popup_message}"/>
</Canvas>
</Popup>
<--CS-->
public partial class MainWindow : Window
{
public string? Popup_message { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
I also tried making an interfacing class of sorts to see if that would work around the stackoverflow error (haha) but as im sure you could have guessed by now, that didn't work either...
Kinda pulling my hair out so any help would be greatly appreciated!
Thanks in advance!
You could just set the Text property of the VerifTextBlock directly as suggested by #Clemens:
private void SmallPopupHandler(string text)
{
VerifTextBlock.Text = text;
verif_popup.IsOpen = true;
}
If you really do want to use a binding for whatever reason, then remove the binding path. This should work:
private void SmallPopupHandler(string text)
{
Binding binding = new()
{
Source = text
};
VerifTextBlock.SetBinding(TextBlock.TextProperty, binding);
verif_popup.IsOpen = true;
}

WPF MVVM Prevent tab change

I am having a WPF Tab control with two tabs called "OFFLINE" & "ONLINE". When "ONLINE" tab click, I need to chek whether application is in online status or not.If (status ! = online)
display error message and prevent displaying "ONLINE" (2nd) tab and go to "OFFLINE" tab.
VIEW.XAML
<TabControl Name="dashboardTabControl" SelectedIndex="{Binding SelectedTabIndex,Mode=TwoWay}">
<TabItem Header="Local Dashboard">
<views:OfflineDashboard DataContext="{Binding OfflineDashboardViewModel}"/>
</TabItem>
<TabItem Header="Online Dashboard">
<views:OnlineDashboard DataContext="{Binding OnlineDashboardViewModel}"/>
</TabItem>
</TabControl>
VIEWMODEL
public int SelectedTabIndex
{
get
{
return this.selectedTabIndex;
}
set
{
if (value == 1 && !applicationData.IsApplicationOnline())
{
this.SelectedTabIndex = 0;
}
else
{
this.selectedTabIndex = value;
}
// TODO : According to the selected tab index , populate ONLINE/OFFLINE
viewmodels
NotifyPropertyChange("SelectedTabIndex");
}
}
Question : Although i checked status and set tab to 0, it doesn't work.
always onclick of 2nd tab it will displayed ONLINE tab.
I would do this the other way around.
Have the ViewModel listen for network changes and expose a bool property Online.
Bind the Enabled property of the Tabpages to this bool.
That way you do not pollute the ViewModel with UI code.
Finally I found a solution for my problem:
XAML
<TabControl Name="dashboardTabControl" Margin="0,5,0,0" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TabItem Header="Local Dashboard" IsSelected="{Binding IsOnline,Converter={StaticResource invertBoolConverter}}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Top">
<views:OfflineDashboard DataContext="{Binding OfflineDashboardViewModel}"/>
</TabItem>
<TabItem Header="Online Dashboard" IsSelected="{Binding IsOnline}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Top">
<views:OnlineDashboard DataContext="{Binding OnlineDashboardViewModel}"/>
</TabItem>
Now I am using IsSelected property of TabItem, instead of SelectedIndex
VIEWMODEL
public bool IsOnline
{
get
{
return isOnline;
}
set
{
// When ONLINE tab click, check whether application is online,
// if not, do not display ONLINE tab
if (value && !applicationData.IsApplicationOnline())
{
isOnline = false;
return;
}
else
{
isOnline = value;
}
LoadTabContent();
NotifyPropertyChange("IsOnline");
}
}
This solved my problem.
You should implement INotifyPropertyChanged in your ViewModel. After changing the SelectedTabIndex notify View that selected index of tab control has been changed via PropertyChanged event of INotifyPropertyChanged.
And in your XAML do
SelectedIndex="{Binding SelectedTabIndex,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}

MVVM binding double click to method using telerik radtreecontrol

I've been working on this problem for a stupid amount of time. It is time to ask for directions despite my inner man saying "don't do it."
I am coding in WPF C# using MVVM design pattern. We try to adhere strictly to the pattern and put nothing in the code behind unless there is no option or it is completely unreasonable to do so. Having said that, I am working with a Telerik RadTreeView. Here is a snippet of it in my XAML:
<telerik:RadTreeView IsExpandOnSingleClickEnabled="True" IsLineEnabled="True" Margin="5"
ItemsSource="{Binding ItemsView}"
SelectedItem="{Binding SelectedWidget, Mode=TwoWay}"
ItemTemplate="{StaticResource NodeTemplate}" />
Currently the tree is working properly so that if you highlight a tree item and click the OK button on the view, all is good. However, I need to also allow the user to double click on one of the tree items. This means I already have a command and method, protected override void OkAction(), in my view model with the needed logic. Telerik supplies a property called ItemDoubleClick that is supposed to supply functionality for the tree item double click. But I can't find anything to allow me to do this in the view model. In other words, how do I do the binding? We also have a behavior setup in our project for double clicking that I was told I could use, but I have no experience with behaviors. I'm still a little wet with WPF.
If it helps, here is a link to the documentation for Telerik: http://www.telerik.com/help/wpf/radtreeview-events-overview.html
I would appreciate any help or direction anyone can provide.
Try this out Stan:
<Grid.Resources>
<DataTemplate x:Key="WidgetTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="/Resources/gear1.png" Margin="1" Stretch="None" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="6,0,0,0" />
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="NodeTemplate" ItemsSource = "{Binding Children}" ItemTemplate="{StaticResource WidgetTemplate}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Grid.Resources>
This is where you are going to want to possibly use the Attached Behavior that you already have for the DoubleClick.
Otherwise, here is the complete code that I use which creates the Attached Behavior and will create two Attached Properties which bind to a Command and optionally a Command Parameter.
AttachedBehaviors.cs
public static class MouseDoubleClick
{
public static DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command",
typeof(ICommand),
typeof(MouseDoubleClick),
new UIPropertyMetadata(CommandChanged));
public static DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter",
typeof(object),
typeof(MouseDoubleClick),
new UIPropertyMetadata(null));
public static void SetCommand(DependencyObject target, ICommand value)
{
target.SetValue(CommandProperty, value);
}
public static void SetCommandParameter(DependencyObject target, object value)
{
target.SetValue(CommandParameterProperty, value);
}
public static object GetCommandParameter(DependencyObject target)
{
return target.GetValue(CommandParameterProperty);
}
private static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
Control control = target as Control;
if (control != null)
{
if ((e.NewValue != null) && (e.OldValue == null))
{
control.MouseDoubleClick += OnMouseDoubleClick;
}
else if ((e.NewValue == null) && (e.OldValue != null))
{
control.MouseDoubleClick -= OnMouseDoubleClick;
}
}
}
private static void OnMouseDoubleClick(object sender, RoutedEventArgs e)
{
Control control = sender as Control;
ICommand command = (ICommand)control.GetValue(CommandProperty);
object commandParameter = control.GetValue(CommandParameterProperty);
if (command.CanExecute(commandParameter))
command.Execute(commandParameter);
}
}
.xaml - Remember to add the namespace of where the Attached Behavior lies.
<telerik:RadTreeView IsExpandOnSingleClickEnabled="True"
IsLineEnabled="True"
Margin="5"
ItemsSource="{Binding ItemsView}"
SelectedItem="{Binding SelectedWidget, Mode=TwoWay}"
ItemTemplate="{StaticResource NodeTemplate}"
acb:MouseDoubleClick.Command="{Binding ShowItemCommand}" />
SampleViewModel.cs
private RelayCommand _showItemCommand;
public RelayCommand ShowItemCommand
{
get
{
return _showItemCommand ?? (_showItemCommand =
new RelayCommand(ShowItemDetails, IsItemSelected));
}
}
obviously I don't have Telerik code so I can't really help as much as i would like to but you can try something like this. (Disclaimer: I am writing from top of my head)
Define your style in Grid.Resources
<Style TargetType="{x:Type RadTreeViewItem }" x:Key="TreeViewItemStyle">
<EventSetter Event="MouseDoubleClick" Handler="{Binding DoubleClick}" />
</Style>
Add the Style to Container Style.
<telerik:RadTreeView IsExpandOnSingleClickEnabled="True" IsLineEnabled="True" Margin="5"
ItemsSource="{Binding ItemsView}"
SelectedItem="{Binding SelectedWidget, Mode=TwoWay}"
ItemTemplate="{StaticResource NodeTemplate}"
ItemContainerStyle ="{StaticResource TreeViewItemStyle}"/>
Let me know if it works.
I tried several ways to get this accomplished.In the end I found that VS2012 was giving me fits. I noticed that changes weren't being applied on a build and run.
I opened VS2010 to find I wasn't experiencing the same issues. After speaking with my boss, we found this to be a good example of a situation that adhering to MVVM may not be the wisest choice since double clicking was strictly UI related.
I simply bounced through the code behind and into the view model using the instantiation of the view model as the data context. Didn't take but a second to do that.
As for the other solutions, I am sure it is completely possible, but I cannot confirm or deny the posts I've made here because of my VS2012 issues.

Binding string to a textbox based on which button is clicked

I have an editor (textbox) and I'd like to bind different texts to it based on which button is clicked.
I could use a command on the button and pass the string which I'd like to edit through commandparameter and update the string which is bound to the textbox. This will work but it's not going to save the modifications because there is no binding between the text (which was passed through the commandparameter) and the textbox's text.
My question is, how should I implement this bind neatly without accessing the textbox directly from the View Model?
edit: it's probably vague what I'm trying to achieve. I try to clarify it a bit:
So let's say I have several different buttons, if I click one of those, it should bind some string to the editor's textbox, where I can modify it and save it later.
<Button Content="Edit query" Command="{Binding ShowQueryInEditorCommand}" CommandParameter="{Binding SomeSqlStringToBeEdited}"/>
<Button Content="Edit query" Command="{Binding ShowQueryInEditorCommand}" CommandParameter="{Binding SomeOtherSqlStringToBeEdited}"/>
This is what the command will execute:
public void ShowQueryInEditor(object o)
{
string SqlStatementParam = o as string;
if (SqlStatementParam != null)
SQLStatement = SqlStatementParam;
}
And the editor TextBox itself:
<TextBox Text="{Binding SQLStatement}">
As you can see, this is very rudimentary as it just sets the SQLStatement string, but there is no bind between them so it cannot reflect the modifications back to SomeSqlStringToBeEdited/SomeOtherSqlStringToBeEdited. This is what I would like to achieve, to bind that string somehow to the textbox when the button is clicked.
There are two basic ways I can think of: through code, or through Xaml.
In code, instead of accessing the textbox from the ViewModel, add a new property to the ViewModel for the "DisplayText" or "SelectedText", or whatever makes sense in your scenario. Bind your textbox to that property instead, and then put the rest of the logic you need inside the setter (or, if it's a DependencyProperty, the OnPropertyChanged callback). That keeps all the logic in your ViewModel and means the Xaml doesn't have to care.
Or in Xaml, you could use triggers and templates to change the textbox depending on the selected button. Most likely form your description, I would suggest having multiple textboxes, one bound to each string, and switch the visible textbox based on the button that's clicked. This keeps your ViewModel ignorant of this display-specific logic, and allows you to change it more easily later on.
Personally, I would likely suggest the Xaml approach, but it will depend on your specific situation.
According to
but the problem is that the buttons are created dynamically
1) Wrap you query text and button into view model like this:
public class ViewModel : ViewModelBase
{
public ViewModel()
{
this.turnIsSelectedOnCommand = new RelayCommand(() => IsSelected = true);
}
public String Text
{
get { return text; }
set
{
if (text != value)
{
text = value;
OnPropertyChanged("Text");
}
}
}
private String text;
public Boolean IsSelected
{
get { return isSelected; }
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
private Boolean isSelected;
public RelayCommand TurnIsSelectedOnCommand
{
get { return turnIsSelectedOnCommand; }
}
private readonly RelayCommand turnIsSelectedOnCommand;
}
2) Put your dynamically created text/buttons into collection. For simplicity, I've added them to array:
public MainWindow()
{
InitializeComponent();
DataContext = new[]
{
new ViewModel { Text = "SELECT * FROM Foo", IsSelected = true },
new ViewModel { Text = "SELECT * FROM Bar" },
new ViewModel { Text = "DROP TABLE Foo" },
new ViewModel { Text = "DROP TABLE Bar" },
};
}
3) Bind the collection with ListBox, and the editor - with the Text of the selected item:
<ListBox Grid.Row="0" Margin="5" ItemsSource="{Binding}" x:Name="lbItems">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Right"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent"/>
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="Edit query" Command="{Binding TurnIsSelectedOnCommand}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Grid.Row="1" Margin="5" Text="{Binding Path=SelectedItem.Text, ElementName=lbItems}" />
I've added some style modifications.
First modifies buttons layout.
Second means, that when you will push the button and ViewModel will become selected, list box item will be selected too.
Third hides selection from the background of the selected item.
Hope, this helps.

Label visible using converter doesn't work,in another way i screwed up

This looks so embarrassing and most awful to ask question again and again for the same thing.
Really sorry but i couldn't still figure it out or not working as expected
in my previous post #slugster suggested converter ,so used his code like below
MyView.xaml
<UserControl.Resources>
<!-- Image Buttons -->
<Converters:BooleanToVisibilityConverter x:Key="visibilityConverter"></Converters:BooleanToVisibilityConverter>
<!--Label-->
<Converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></Converters:BooleanToVisibilityConverter>
<Label Name="isImageValid" Content="Image not Created" Margin="0,7,1,0" Style="{StaticResource LabelField}"
Grid.ColumnSpan="2" Grid.Row="15" Width="119" Height="28" Grid.RowSpan="2"
Grid.Column="1" IsEnabled="True"
Visibility="{Binding isImageValid,Converter={StaticResource BooleanToVisibilityConverter}}" />
myviewModel.cs
private bool _isImageValid;
public bool IsImageValid
{
get { return _isImageValid; }
set
{
_isImageValid = value;
this.RaisePropertyChanged(() => this.IsImageValid);
}
}
private void OnImageResizeCompleted(bool isSuccessful)
{
if (isSuccessful)
{
this.SelectedStory.KeyframeImages = true;
_isImageValid = false;
// isImageValid = System.Windows.Visibility.Collapsed;
}
else
this.SelectedStory.KeyframeImages = false;
}
when i debug the code,its not even reflect in the UI,when "OnImageResizeCompleted" method called and "_isImageValid=False".Again am lost now.I know i get lot of negative comments but sorry i couldn't able to figure it out myself.
First, correct Visibility="{Binding isImageValid... line. Your view model property is IsImageValid.
Second, OnImageResizeCompleted() method does not notify UI about IsImageValid property changes, it simply modifies property backing field. Change _isImageValid = false to IsImageValid = false.

Categories

Resources