best approach to open a pop up window for large data - wpf

i am new to wpf and i need to open up a pop up a new window on grid row click which contains lots of data and controls on it.i am confused with the correct approach. i am using mvvm pattern.should i make a window control or user control or something else. and how to open that pop up inside a function. please help with example

If I need to display a new Window in my MVVM-Application I use the following approach:
At first I have an interface with a method to show the new dialog:
internal interface IDialogManager
{
void DisplayData(object data);
}
And an implementation like:
internal class DialogManager : IDialogManager
{
public void DisplayData(object data)
{
LotOfDataViewModel lotOfDataViewModel = new LotOfDataViewModel(data);
LotOfDataView lotOfDataView = new LotOfDataView
{
DataContext = lotOfDataViewModel
};
lotOfDataView.ShowDialog();
}
}
LotOfDataViewModel and LotOfDataView are the new Dialog where you want to show your data.
In your actual ViewModel you introduce a new property like:
private IDialogManager dialogManager;
private IDialogManager DialogManager
{
get { return dialogManager ?? (dialogManager = new DialogManager()); }
}
And the you can show your large data with:
DialogManager.DisplayData(myData);

Related

Windows 10 Universal App - ListView Update from Background Thread

I have a strange problem here. We develop a Windows 10 Universal App and now I want to update my listview when I add new value. But unfortunately it wont work and I dont really know why. When I add new value it won't update my list view.
The data comes from a background-thread (REST-Request against Server) and therefore I know, I should use something that runs the "add-functionality" on the UI-Thread.
First of all I declared a IProgress and my collection:
private List<dtoGemeinde> _listeGemeinden = new List<dtoGemeinde>();
public List<dtoGemeinde> GemeindenCollection
{
get { return this._listeGemeinden; }
}
IProgress<dtoGemeinde> prog;
prog = new Progress<dtoGemeinde>(UpdateListViewUI);
This is the "UpdateListViewUI" method:
public void UpdateListViewUI(dtoGemeinde dto)
{
_listeGemeinden.Add(dto);
this.listViewGemeinden.ItemsSource = GemeindenCollection;
}
And this is the callback method which is called when the background thread, which loads the data from the server, is finished:
public async void onCallBackGemeinden(List<dtoGemeinde> listeGemeinden)
{
if (listeGemeinden != null && listeGemeinden.Count > 0)
{
this.progress.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
foreach (dtoGemeinde dto in listeGemeinden)
{
await listViewGemeinden.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => prog.Report(dto));
}
}
else
{
await new MessageDialog("Data cant be load", "Error").ShowAsync();
}
}
ObservableCollection instead of List usually works fine if need to bind a ListView and be able to see the updates, if this doesn't work any underlying class might need to implement the INotifyChanged pattern to update any properties within the collection if needed.

Pattern for binding commands on a child ViewModel from a parent menu

I'm creating a WPF MVVM app using Caliburn Micro. I have a set of buttons in a menu (Ribbon) that live in the view for my shell view model, which is a ScreenConductor. Based on the currently active Screen view model, I would like to have the ribbon buttons be disabled/enabled if they are available for use with the active Screen, and call actions or commands on the active Screen.
This seems like a common scenario. Is there a pattern for creating this behavior?
Why don't you do the reverse thing, instead of checking which commands are supported by the current active screen, let the active screen populate the menu or ribbon tab with all the controls that it supports, (i would let it inject its own user control which might just be a complete menu or a ribbon tab all by itself), this will also enhance the user experience as it will only show the user the controls that he can work with for the current active screen.
EDIT: Just looking at your question again and I'm thinking that this is much simpler than it looks
The only issue I can see you having is that a lack of a handler (and guard) method on a child VM will mean that buttons that don't have an implementation on the currently active VM will still be enabled.
The default strategy for CM is to try and find a matching method name (after parsing the action text) and if one is not found, to leave the button alone. If you were to customise that behaviour so that the default is for buttons to be disabled, you could easily get it working by just implementing the command buttons in your shell, making sure to set the command target to the active item:
In the shell define your buttons, making sure they have a target that points to the active child VM
<Button cal:Message.Attach="Command1" cal:Action.TargetWithoutContext="{Binding ActiveItem}" />
Then just implement the method in your child VM as per usual
public void Command1() { }
and optionally a CanXX guard
public bool CanCommand1
{
get
{
if(someCondition) return false;
return true;
}
}
Assuming you don't get much more complex than this, it should work for you
I'm going to have a quick look at the CM source and see if I can come up with something that works for this
EDIT:
Ok you can customise the ActionMessage.ApplyAvailabilityEffect func to get the effect you want - in your bootstrapper.Configure() method (or somewhere at startup) use:
ActionMessage.ApplyAvailabilityEffect = context =>
{
var source = context.Source;
if (ConventionManager.HasBinding(source, UIElement.IsEnabledProperty))
{
return source.IsEnabled;
}
if (context.CanExecute != null)
{
source.IsEnabled = context.CanExecute();
}
// Added these 3 lines to get the effect you want
else if (context.Target == null)
{
source.IsEnabled = false;
}
// EDIT: Bugfix - need this to ensure the button is activated if it has a target but no guard
else
{
source.IsEnabled = true;
}
return source.IsEnabled;
};
This seems to work for me - there is no target for methods which couldn't be bound to a command, so in that case I just set IsEnabled to false. This activates buttons only when a method with a matching signature is found on the active child VM - obviously give it a good test before you use it :)
Create methods and accompanying boolean properties for each of your commands on your shell view model. (See code below for an example.) Caliburn.Micro's conventions will wire them up to the buttons for you automatically. Then simply raise property changed events for the boolean properties when you change views to have them be re-evaluated.
For example, let's say you have a Save button. The name of that button in your xaml would be Save, and in your view model, you would have a Save method along with a CanSave boolean property. See below:
public void Save()
{
var viewModelWithSave = ActiveItem as ISave;
if (viewModelWithSave != null) viewModelWithSave.Save();
}
public bool CanSave { get { return ActivateItem is ISave; } }
Then, in your conductor, whenever you change your active screen, you would call NotifyOfPropertyChange(() => CanSave);. Doing this will cause your button to be disabled or enabled depending upon if the active screen is capable of dealing with that command. In this example, if the active screen doesn't implement ISave, then the Save button would be disabled.
I would use the Caliburn.Micro event aggregation in this scenario, as follows:
Create a class named ScreenCapabilities with a bunch of Boolean attributes (e.g. CanSave, CanLoad, etc.)
Create a message named ScreenActivatedMessage with a property of type ScreenCapabilities
Create a view model for your ribbon that subscribes to (handles) the ScreenActivatedMessage
In the ribbon view model's Handle method, set the local CanXXX properties based on the supplied ScreenCapabilities.
It would look something like this (code typed by hand, not tested):
public class ScreenCapabilities
{
public bool CanSave { get; set; }
// ...
}
public class ScreenActivatedMessage
{
public ScreenCapabilities ScreenCapabilities { get; set; }
// ...
}
public class RibbonViewModel : PropertyChangedBase, IHandle<ScreenActivatedMessage>
{
private bool _canSave;
public bool CanSave
{
get { return _canSave; }
set { _canSave = value; NotifyPropertyChanged(() => CanSave); }
}
// ...
public void Handle(ScreenActivatedMessage message)
{
CanSave = message.ScreenCapabilities.CanSave;
// ...
}
}
Then, somewhere appropriate, when the screen changes, publish the message. See see Caliburn.Micro wiki for more info.
Define a property (let's say ActiveScreen) for the active screen in the shell view model.
And let's assume you have properties for the each button such as DeleteButton, AddButton.
Screen is a viewmodel for the screens.
private Screen activeScreen;
public Screen ActiveScreen
{
get
{
return activeScreen;
}
set
{
activeScreen= value;
if (activeScreen.Name.equals("Screen1"))
{
this.AddButton.IsEnabled = true;
this.DeleteButton.IsEnabled = false;
}
if else (activeScreen.Name.equals("Screen2"))
{
this.AddButton.IsEnabled = true;
this.DeleteButton.IsEnabled = true;
}
NotifyPropertyChanged("ActiveScreen");
}
}

Eclipse WizardPage for exporting a file

I want to use the exportWizard extension point for an eclipse plugin. I am having some difficulties figuring out how a simple filedialog wizard page should look like.
public class ExportWizardPage extends WizardPage {
private FileDialog fileDialog=null;
protected ExportWizardPage(String pageName) {
super(pageName);
}
#Override
public void createControl(Composite parent) {
fileDialog = new FileDialog(parent.getShell(), SWT.SAVE);
fileDialog.setFilterExtensions(new String[] { "*.bm" });
}
}
I am trying it currently like above and use a FileDialog for selecting the target file. Basically it works, the dialog is opened and I get the name of the file, but as soon the dialog closes I get an exception.
org.eclipse.core.runtime.AssertionFailedException: null argument:
at org.eclipse.core.runtime.Assert.isNotNull(Assert.java:85)
at org.eclipse.core.runtime.Assert.isNotNull(Assert.java:73)
at org.eclipse.jface.wizard.Wizard.createPageControls(Wizard.java:178)
I think I am using this Wizard/WizardPage mechanism wrongly, but I really could not found a simple example that showed me how something should look like.
Your wizard page does not contain any controls. You should create one composite and then add all your controls to it (and NOT parent directly). Calling setControl(..) is also absolutely required. It should look something like this:
#Override
public void createControl(Composite parent) {
Composite content = new Composite(parent, SWT.NONE);
// add all the controls to your wizard page here with 'content' as parent
FileDialog fileDialog = new FileDialog(parent.getShell(), SWT.SAVE);
fileDialog.setFilterExtensions(new String[] { "*.bm" });
setControl(content);
}

Failing to display a custom WPF dialog box more than one time

I am trying to display a custom dialog box multiple times using the following code:
TestWindow newTestWindow = new TestWindow(test);
newTestWindow.Owner = this;
newTestWindow.ShowDialog();
And I get the following exception when running the code above for the 2nd time:
Specified element is already the logical child of another element. Disconnect it first.
Chances are you are trying to display the same element in both dialogs (maybe the test parameter)? You would need to disconnect the element from the dialog when it's closed, so that it can be used in any subsequent dialogs.
Works fine for me:
public partial class MainWindow : Window
{
private Test _newTestWindow;
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
private void OnLoaded( object sender, RoutedEventArgs e )
{
_newTestWindow = new Test { Owner = this };
_newTestWindow.ShowDialog();
_newTestWindow = new Test { Owner = this };
_newTestWindow.ShowDialog();
}
}

Unit test WPF Bindings

I am trying to unit test my WPF databindings using the test suit provided by Microsoft Team System. I would like to be able to test the bindings without showing the window because most of my tests will be for user controls and not actually on a window. Is this possible or is there a better way to do it? The code below works if I show the window, but if I don't, the bindings don't update.
Window1_Accessor target = new Window1_Accessor();
UnitTestingWPF.Window1_Accessor.Person p = new UnitTestingWPF.Window1_Accessor.Person() { FirstName = "Shane" };
Window1 window = (target.Target as Window1);
window.DataContext = p;
//window.Show(); //Only Works when I actually show the window
//Is it possible to manually update the binding here, maybe? Is there a better way?
Assert.AreEqual("Shane", target.textBoxFirstName.Text); //Fails if I don't Show() the window because the bindings aren't updated
While looking for a solution to convert WPF binding errors into exception, I figured out that it can also be used in a unit test project.
The technique is very simple:
Derive a TraceListener that throws instead of logging
Add that listener to PresentationTraceSources.DataBindingSource
Please see the complete solution on GitHub, it includes a unit test project.
Shane, if what you're really worried about is a binding breaking silently, you should look at redirecting the binding traces to somewhere you can examine. I'd start here:
http://blogs.msdn.com/mikehillberg/archive/2006/09/14/WpfTraceSources.aspx
Other than that, I agree with Gishu that bindings aren't good candidates for unit testing, mainly due to the automagic going on that Gishu mentioned in the "Epilogue". Instead focus on making sure the underlying class behaves correctly.
Note, too, that you can get even more robust traces using the PresentationTraceSources class:
http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.aspx
Hope that helps!
Eyeball it.
This kind of declarative markup rarely breaks.. unless someone goes in manual and screws it up. Even then, you can fix it within minutes. IMHO the cost of writing such tests far outweigh the benefits.
Update[Dec3,08]: Alrighty then.
The test is just testing that the textbox has the value "FirstName" as the Path property of the binding. If I change/refactor FirstName to JustName in the actual data source object, the test would still pass since it is testing against an anonymous type. (Green test when code broken - TDD Antipattern: The Liar)
If your aim is to verify that FirstName has been specified in XAML,
Assert.AreEqual("FirstName", txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).ParentBinding.Path.Path);
If you really must catch broken bindings via unit tests (and don't want to show the UI), use the real data source... struggled for a while and came up with this.
[Test]
public void TestTextBoxBinding()
{
MyWindow w = new MyWindow();
TextBox txtBoxToProbe = w.TextBox1;
Object obDataSource = w; // use 'real' data source
BindingExpression bindingExpr = BindingOperations.GetBindingExpression(txtBoxToProbe, TextBox.TextProperty);
Binding newBind = new Binding(bindingExpr.ParentBinding.Path.Path);
newBind.Source = obDataSource;
txtBoxToProbe.SetBinding(TextBox.TextProperty, newBind);
Assert.AreEqual("Go ahead. Change my value.", txtBoxToProbe.Text);
}
Epilogue:
There's some real covert stuff happening in the call to Window.Show(). It somehow magically sets up the DataItem property after which data binding starts working.
// before show
bindingExpr.DataItem => null
bindingExpr.Status => BindingStatus.Unattached
// after show
bindingExpr.DataItem => {Actual Data Source}
bindingExpr.Status => BindingStatus.Active
Once the Binding is Active, I guess you can force textbox updates via code like this..
txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
Once again, I voice my reluctance against this approach. Getting NUnit to run in STA was a pain..
Combining advice I came across in a number of SO posts I wrote the following class which works very well to test WPF bindings.
public static class WpfBindingTester
{
/// <summary>load a view in a hidden window and monitor it for binding errors</summary>
/// <param name="view">a data-bound view to load and monitor for binding errors</param>
public static void AssertBindings(object view)
{
using (InternalTraceListener listener = new InternalTraceListener())
{
ManualResetEventSlim mre = new ManualResetEventSlim(false);
Window window = new Window
{
Width = 0,
Height = 0,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false,
ShowActivated = false,
Content = view
};
window.Loaded += (_, __) => mre.Set();
window.Show();
mre.Wait();
window.Close();
Assert.That(listener.ErrorMessages, Is.Empty, listener.ErrorMessages);
}
}
/// <summary>Is the test running in an interactive session. Use with Assume.That(WpfBindingTester.IsAvailable) to make sure tests only run where they're able to</summary>
public static bool IsAvailable { get { return Environment.UserInteractive && Process.GetCurrentProcess().SessionId != 0; } }
private class InternalTraceListener : TraceListener
{
private readonly StringBuilder _errors = new StringBuilder();
private readonly SourceLevels _originalLevel;
public string ErrorMessages { get { return _errors.ToString(); } }
static InternalTraceListener() { PresentationTraceSources.Refresh(); }
public InternalTraceListener()
{
_originalLevel = PresentationTraceSources.DataBindingSource.Switch.Level;
PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
PresentationTraceSources.DataBindingSource.Listeners.Add(this);
}
public override void Write(string message) {}
public override void WriteLine(string message) { _errors.AppendLine(message); }
protected override void Dispose(bool disposing)
{
PresentationTraceSources.DataBindingSource.Listeners.Remove(this);
PresentationTraceSources.DataBindingSource.Switch.Level = _originalLevel;
base.Dispose(disposing);
}
}
}
you can try Guia.
With it you can unit-test your UserControl and check if the data binding is correct. You have to show the window though.
Here is an example. It starts a new instance of your UserControl and sets its DataContext and then checks if the textbox is set to the right value.
[TestMethod]
public void SimpleTest()
{
var viewModel = new SimpleControlViewModel() {TextBoxText = "Some Text"};
customControl = CustomControl.Start<SimpleUserControl>((control) => control.DataContext = viewModel);
Assert.AreEqual("Some Text", customControl.Get<TextBox>("textbox1").Value);
customControl.Stop();
}

Resources