I am using MVVM Light WPF 4.
I have a ContentPresenter in my Home.xaml.
<ContentPresenter Name="MDI" Content="{Binding WindowName, Mode=OneWay}">
I am binding user control to this in viewmodel like
public UserControl WindowName { get; set; }
void ShowSalesEntry()
{
WindowName = null;
WindowName = new SalesEntry();
RaisePropertyChanged("WindowName");
}
by using command in a menu click and it is binding fine.
Now in the user control i have a button which i used to close (but to close i change the visibility
to collapsed) by this way..
Visibility="{Binding visibility, Mode=OneWay}"
in the user control view model,
public SalesEntryViewModel()
{
visibility = Visibility.Visible;
cmdExitWindow = new RelayCommand(ExitWindow);
RaisePropertyChanged("visibility");
}
and the following to close (visibility to collapsed)
public RelayCommand cmdExitWindow { get; set; }
void ExitWindow()
{
visibility = Visibility.Hidden;
RaisePropertyChanged("visibility");
}
To exit (means visibility collapsed)..
This is working fine upto this.
Problem is when i click the same page i mean to show the same user control,
now this time the visibility is still collapsed. Even though i changed to visible in the
load event.
How to solve this..
I am new to MVVM WPF.. Please help me..
Problem is when i click the same page i mean to show the same user
control, now this time the visibility is still collapsed. Even though
i changed to visible in the load event.
Based on this comment and the code provided, you've either omitted code, or you've confused the purpose of the constructor.
In your constructor, you have set the Visibility to Visible. You then have a method that sets the Visibility to Hidden, but there is nothing to ever set it back to Visible once this has occurred. The constructor only fires when the object is created. You need something to set the Visibility back at the appropriate time (ie. your comment "when i click the same page").
//Add these lines to the method/event that will show the control again
visibility = Visibility.Visible;
RaisePropertyChanged("visibility");
That's the best answer I can give based on what you've provided.
Related
I am using MVVM. On my View I have a control that by default is hidden, it's Visibility property is Binded to ViewModels property.
<Grid>
<TextBox Visibility={Binding IsVisible, Mode=OneWay, Converter={StaticResource MyVisibilityConverter}}/>
<Grid>
In the ViewModel I have a property
private bool _isVisible;
bool IsVisible
{
get {return _isVisible;}
set {_isVisible = value; NotifyOfPropetyChanged(() => IsVisible);}
}
pretty much straighforward, to show the control I just do
IsVisible = true;
in my ViewModel and the TextBox becomes visible, works fine as intended.
What I want to do is to set Focus on the TextBox just after it becomes visible. The problem is that I can't find any good solution how to determine that this particular control just got visible and it is the moment I can set the focus.
The solution would be to test the visibility inside LayoutUpdated event, but it is definitely not the nicest thing to have in code.
Any better solution?
edit:
To clarify - I don't want to set the focus via MVVM from the ViewModel. There is no problem in setting the focus from the code-behind as it is the UI behaviour. The only problem is how to determine WHEN to do that. There is a some period of time beetween the ViewModel property is set and the layout being updated to match its state. After that perdiod of time I want to be able to catch anything that can notify me "my visibility has changed, now you can change focus"
You could use RegisterPropertyChangedCallback to register a change callback for the Visibility property of the textbox. then in the changed call back method you can set the focus is the visibility is visible.
Put this in the constructor of the code behind:
TextBox1.RegisterPropertyChangedCallback(UIElement.VisibilityProperty, VisibilityChanged);
and add the CallBack method:
private void VisibilityChanged(DependencyObject sender, DependencyProperty dp)
{
if (((UIElement)sender).Visibility == Visibility.Visible)
{
TextBox1.Focus(FocusState.Keyboard);
}
}
I created an application with WPF and C# (no MVVM), I have 3 user controls containing grids, forms and others things. but finaly I wanted to add a login user control (each user control is standalone), the way I started to build it, is to set by default all the user controls visibility in xaml to collapsed except for the login usercontrol which will be collapsed after a successful login :
public static DependencyProperty WindowVisibilityProperty = DependencyProperty.Register("WindowVisibility", typeof(Visibility), typeof(MemberStats), null);
public Visibility WindowVisibility
{
get
{
return (Visibility)GetValue(WindowVisibilityProperty);
}
set
{
SetValue(WindowVisibilityProperty, value);
}
}
But I don't know how to use Dependency proprety for multiple in the xaml of the user controls,a simple way with explanation or any help would be appreciated .
In the window tag add x:Name="SomeName".
Then bind to the local property like this.
Visibility="{Binding WindowVisibility, ElementName=SomeName}"
I have a user control that has a TextBox on it. If I set focus on the TextBox in the constructor, then the TextBox works as expected. Sometimes though, I don't want the TextBox to have focus when the user control is first shown, and so I added a property to the user control which sets focus to the TextBox. This works, although I get the problem that I can't then reset focus on the TextBox after it has lost focus.
Doesn't anyone have any ideas why this might be happening?
public ucQueryBox()
{
InitializeComponent();
// Set default values for properties
CodePrompt = "Barcode";
TextBoxFontSize = 20;
TextBoxMaxWidth = 0;
Label = "";
LabelFontSize = 20;
LabelForeground = Colors.White.ToString();
KeyboardButtonVisibility = Visibility.Visible;
txtSelection.Focus();
}
/// <summary>
/// Allows user to decide whether or the user control should have focus when it loads
/// Focus puts the green boarder around the textbox
/// </summary>
[Browsable(true)]
public Boolean SetFocusOnLoad
{
get { return _bSetFocusOnLoad; }
set
{
_bSetFocusOnLoad = value;
if (_bSetFocusOnLoad)
txtSelection.Focus();
}
}
Focus in WPF is a complex topic. I think you'll find that the proper way to do what you want is to use FocusManager in your XAML:
<UserControl ... FocusManager.FocusedElement="{Binding ElementName=myTextBox}">
<TextBox x:Name="myTextBox" />
</UserControl>
If you use FocusManager like this to establish all focus requirements (that is, you use FocusManager on all Windows and UserControls that have any sort of focus requirements), then you'll probably find that all the focusing works exactly like you expect.
I have a ComboBox in a WPF app that has recently been refactored to use the MVVM pattern. An apparent side effect to this change is that changing focus to another application while the combobox dropdown is visible completely prevents the dropdown from being visible again, until the app has been restarted.
The ComboBox DataContext is set to my ViewModel, with its ItemsSource bound to an ObservableCollection<String> SearchSuggestions, and IsDropdownOpen bound to a property SuggestionsVisible in the ViewModel.
The desired effect is a search box with autocomplete suggestions. It should close if there are no suggestions in the ObservableCollection, if the user cancels the search, if the user runs the search, or if the user clicks away from the text field - either inside the app or outside it.
The ViewModel explicitly sets the SuggestionsVisible property to true or false based on whether SearchSuggesions contains any items after user input. This process continues to take place after this bug manifests itself, just with no visible change to the UI. Any idea why losing focus while the dropdown is open renders the dropdown un-openable for the rest of the app's session?
Here's how I have things wired together:
<ComboBox DataContext="{Binding SearchBoxVm}" Name="cmboSearchField" Height="0.667"
VerticalAlignment="Top" IsEditable="True" StaysOpenOnEdit="True"
PreviewKeyUp="cmboSearchField_OnKeyUp"
PreviewMouseLeftButtonUp="cmboSearchField_OnPreviewMouseLeftButtonUp"
Background="White" ItemsSource="{Binding SearchTopics}"
IsDropDownOpen="{Binding SuggestionsVisible,
UpdateSourceTrigger=PropertyChanged}"
Margin="50.997,15.333,120.44,0"
RenderTransformOrigin="0.5,0.5" Grid.Row="1" >
<!-- SNIP STYLING -->
</ComboBox>
ViewModel:
public class SearchBoxViewModel : INotifyPropertyChanged
{
public void ResetSearchField(bool preserveContents = false)
{
if (!preserveContents || string.IsNullOrEmpty(Query))
{
Foreground = Brushes.Gray;
QueryFont = FontStyles.Italic;
Query = DEFAULT_TEXT;
}
}
public bool OnKeyUp(Key key)
{
bool showDropdown = SuggestionsVisible;
bool changeFocusToCombobox = false;
if (keyInValidRange(key))
{
SearchSuggestions = GetSearchSuggestions(Query);
if (SearchSuggestions.Count > 0)
{
SuggestionsVisible = true;
}
}
return changeFocusToCombobox;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
bool _suggestionsVisible = false;
public bool SuggestionsVisible
{
get { return _suggestionsVisible; }
set
{
// this section is still called after this issue manifests,
// but no visible change to the UI state is made
_suggestionsVisible = value;
NotifyPropertyChanged("SuggestionsVisible");
}
}
public ObservableCollection<String> SearchTopics = new ObservableCollection<String>();
}
The OnKeyUp() method is called by the MainWindow class ( haven't gotten as far as binding events to handlers specified in the ViewModel ), while but there's also a call to ResetSearechField from the MainWindow:
// Note: removing references to this event handler does not have any effect
// on the issue at hand... only including here for completeness
void window_Deactivated(object sender, EventArgs e)
{
SearchBoxVm.SuggestionsVisible = false;
SearchBoxVm.ResetSearchField(true);
}
I've spent quite a bit of time trying to debug this, and haven't seen any internal state changes that might account for this. The NotifyPropertyChanged event is otherwise behaving as it did before, and the stack trace window isn't showing any exceptions having been encountered.
Setting the binding mode on the IsDropdownOpen property to 'TwoWay' in the XAML hasn't had any effect either. Lastly, wrapping the assignment to SuggestionsVisible in a Dispatcher call on the main thread has had no effect on the issue either.
Any assistance would be appreciated.
#BrMcMullin, since you have stated that:
The desired effect is a search box with autocomplete suggestions.
may I ask, why do you choose to use standard ComboBox instead of specialized AutoCompleteBox that is available in the WPF Toolkit - February 2010 Release and seems like was especially designed for your case?
You may have noticed that first link points to documentation for its Silverlight predecessor, but don't worry - WPF Toolkit library include fully functional official WPF port of AutoCompleteBox from Silverlight. There is more info about this "event": AutoCompleteBox: Now with 100% more WPF.
With that control your auto complete popup could looks as simple as:
or as complex as:
So, if you will not manage to solve your issue with ComboBox's popup visibility, feel free to give a try to AutoCompleteBox. With it you could even leverage dynamic sorting of your suggestions if needed (just use answer from #adabyron).
I have a user interface with a TabControl that initially displays a start page. Other items can be added to it by double-clicking on content in, for example, a DataGrid. New tabs should be selected when they are created. If the document corresponding to the item in the grid is already open, then the existing tab for that document should be opened rather than creating a new one.
I know that I should be able to programmatically select a tab by setting the TabControl's SelectedItem or SelectedIndex properties. However, the desired tab never actually activates. If I set one and then inspect the TabControl's state in the debugger, then both fields seem to update properly. However, after I continue execution, I see that the selected tab remains unchanged in the UI, and if I pause and inspect the TabControl's state again I see that the SelectedItem and SelectedIndex have returned to their previous values. Selecting a tab by clicking on it in the UI, on the other hand, works just fine.
Here's the declaration for the TabControl:
<TabControl x:Name="Tabs" >
<TabItem x:Name="StartPageTab" Header="Start Page" DataContext="{Binding Path=StartPageViewModel}">
...
</TabItem>
</TabControl>
And the code for adding and selecting tabs:
private void _SelectTab(MyViewModel model)
{
TabItem tab;
if (_TryFindTab(model, out tab)) Tabs.SelectedItem = tab;
}
private bool _TryFindTab(MyViewModel target, out TabItem tab)
{
foreach (TabItem item in Tabs.Items)
{
MyViewModel model = item.DataContext as MyViewModel;
if (model != null && model.Equals(target))
{
tab = item;
return true;
}
}
tab = null;
return false;
}
private void _AddTab(MyViewModel model)
{
TabItem tab = new TabItem { DataContext = model, Content = new MyView() };
Binding bind = new Binding { Source = model, Path = new PropertyPath("Name") };
tab.SetBinding(TabItem.HeaderProperty, bind);
Tabs.Items.Add(tab);
Tabs.SelectedItem = tab;
}
It turned out to be related to something I conveniently omitted from the original problem description:
The DataGrid in question was in the content for StartPageTab. I was handling double-clicks on that DataGrid by capturing its MouseDoubleClick event, searching the visual tree to find what DataGridRow was double-clicked (if any), and then raising an event that would eventually be captured by the main window, which would respond by calling either _SelectTab or _AddTab, depending on whether the document in question was already open.
At which point, the call stack would unroll and get back to that MouseDoubleClick event handler. In that handler, I forgot to set the MouseButtonEventArgs's Handled property to true. So WPF kept searching for someone else to handle that click event - and the element that it eventually found would respond by asking for focus, which in turn meant that the original tab needed to get focus back.
Adding e.Handled = true; stopped that whole mess in its tracks, so the new tab could stay selected.
You could try using tab.focus()
I have tabs in my application and this is a quick way to make your selected tab visible.
Have you tried binding to TabItem.IsSelected and updating that in you view model?
In an older C# app I had, using page controls, I was able to force the page active by telling the tab control object to select the tab...
MyTabControlWithMultiplePages.SelectTab(PageIWantShown);