I have created my own messagebox window which is working however this is how I currently use it:
var msgbox = new msgbox("Please confirm patients phone number with them before proceeding");
msgbox.ShowDialog();
I want to be able to use it this way:
MessageBox.Show("Choose an Estimated Time of Arrival");
This is first of all so i can just replaceAll MessageBox with msgbox. I have lots in my application and now that I have my own custom messagebox it will be so much easier to replace this way rather than replacing with the first set of code.
The issue is I can't figure out how to have the overloads in the showDialog section?
There is probably more than one solution but I would create a new MyMessageBox class with Show method and I would create msgbox inside this method.
public sealed class MyMessageBox
{
public static bool? Show(string messageBoxText)
{
var msgbox = new msgbox(messageBoxText);
return msgbox.ShowDialog();
}
}
Then just replace all MessageBox with MyMessageBox.
System.Windows.MessageBox.Show returns MessageBoxResult, so you can create Show method that returns also MessageBoxResult.
public sealed class MyMessageBox
{
public static MessageBoxResult Show(string messageBoxText)
{
var msgbox = new msgbox(messageBoxText);
msgbox.ShowDialog();
return MessageBoxResult.OK;
}
}
Related
In my application, I need a system where some messages shown to the user have a "do not show again" checkbox. In the Settings menu, I want to have a section "dismissed messages" with names of messages and a checkbox by each, so the user can un-dismiss them if needed. If the message is dismissed, the last choice user selected in the message dialog should become a default one.
Additionally, settings should be saved to an XML file - including the message suppression state and the default choice. My current solution is very crude, and I'd like to know if there is a better way.
The message class is defined as:
Public Class Message
Public Property title As String
Public Property content As String
Public Property buttons As Utilities.Enums.messageButtonTypes 'Ok/Cancel, Yes/No, etc.
Public Property allowDoNotShowAgain As Boolean = False 'whether the message is dismissable
Public Property doNotShowAgain As Boolean = False 'the actual dismiss state
Public Property result As Boolean
Public Property rememberedResult As Boolean 'last user choice if the message is dismissed
End Class
Specific messages are initialized in the MSG module:
Module Msg
'This message is not dismissable
Public connectionNotEstablished As New Message() With {
.title = "Connection not established",
.content = "Connection not established. Please check if the host application is running.",
.buttons = Utilities.Enums.messageButtonTypes.Ok
}
'This message is dismissable
Public noResultsPlotsDefined As New Message() With {
.title = "No plots defined",
.content = "You have not defined any plots. Would you like to run the study anyway?",
.buttons = Utilities.Enums.messageButtonTypes.YesNo,
.allowDoNotShowAgain = True
}
'Just a list to store references to all the messages for binding, looping, etc.
Public allMessages As New List(Of Message) From {
connectionNotEstablished,
noResultsPlotsDefined
}
Public Function ShowMessage(message As Message) As Boolean
If message.doNotShowAgain Then message.result = message.rememberedResult : Return message.rememberedResult 'If message is dismissed, return the last user choice
Dim messageDialog As New MessageDialog(message.title, message.content, message.buttons, message.allowDoNotShowAgain, message.defaultButtonCustomCaption, message.cancelButtonCustomCaption)
message.result = messageDialog.ShowDialog()
message.doNotShowAgain = messageDialog.doNotShowAgain
If message.doNotShowAgain Then message.rememberedResult = message.result
Return message.result
End Function
End Module
Specific messages are called in various functions, for example, like this:
Msg.ShowMessage(connectioNotEstablished)
So far, this is easy enough - very convenient to use while building my application. Now, the bit that I'm not sure about - the AppSettings class. Like I said, I need to store some of the properties of each message, so that I can WPF-bind to the message list in the settings window. Right now, the AppSettings has a reference to the MSG class messages list:
Public Class AppSettings
Public Property messages As List(Of Message) = Msg.allMessages
Public Sub SaveToDefaultPath()
Save(Constants.Paths.settingsFilePath)
End Sub
Private Sub Save(ByVal filename As String)
Using sw As StreamWriter = New StreamWriter(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
xmls.Serialize(sw, Me)
End Using
End Sub
Private Function Read(ByVal filename As String) As AppSettings
Using sw As StreamReader = New StreamReader(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
Return TryCast(xmls.Deserialize(sw), AppSettings)
End Using
End Function
End Class
In my settings WPF window, I can then bind to the messages property, and choose to show the title as TextBlock, doNotShowAgain as a CheckBox, and rememberedResult as a ComboBox. I haven't done that bit yet, but I think it should be pretty straightforward with current application architecture.
Problem is the serialization and de-serialization to and from XML (see the last two functions of the AppSettings class). Since this class stores the references to the whole messages list, which has not just title, doNotShowAgain and rememberedResult, but also the message content and it's other properties, which really clutter that XML file.
I am not sure how to solve this. I could, perhaps, store only the required variables of each message in the AppSettings, but that would require some kind of two-way converter or something. And by this point I'm starting to doubt if this is really the right way to achieve what I need.
I can't be the first one implementing this, so maybe there is a convention for such a thing. Any suggestions?
EDIT: while waiting for answers, I have successfully implemented saving the message dismiss states to XML - unfortunately, it saves the whole message class data, instead of just the title, doNotShowAgain and rememberedResult. To make this work, I had to make only one small change - the property messages in AppSettings was declared as an Array rather than as a List, so that the XML deserializer wouldn't append messages to that List, but instead, would just replace it as a whole.
Public Class AppSettings
Public Property Messages() As Message() = Msg.allMessages.ToArray()
...
End Class
So while this works (binding these messages to WPF window also works), the XML file is cluttered with unnecessary values for each message, for example:
<Message>
<title>No plots defined</title>
<content>You have not defined any plots. Would you like to run the study anyway?</content>
<buttons>YesNo</buttons>
<allowDoNotShowAgain>true</allowDoNotShowAgain>
<doNotShowAgain>false</doNotShowAgain>
<result>false</result>
<rememberedResult>false</rememberedResult>
</Message>
But for this use case, it would be more than enough to have only this bit for each message in the XML file:
<Message>
<title>No plots defined</title>
<doNotShowAgain>false</doNotShowAgain>
<rememberedResult>false</rememberedResult>
</Message>
So my question remains - what is the best solution here? Am I even in the ballpark?
It appears your only problem is having clutter in the Xml file. So you can tell the serializer to ignore certain properties with <XmlIgnore>
Public Class Message
Public Property title As String
<XmlIgnore>
Public Property content As String
<XmlIgnore>
Public Property buttons As Utilities.Enums.messageButtonTypes 'Ok/Cancel, Yes/No, etc.
<XmlIgnore>
Public Property allowDoNotShowAgain As Boolean = False 'whether the message is dismissable
Public Property doNotShowAgain As Boolean = False 'the actual dismiss state
<XmlIgnore>
Public Property result As Boolean
Public Property rememberedResult As Boolean 'last user choice if the message is dismissed
End Class
The serializer will neither serialize nor deserialize those properties.
Now you can also serialize a subset of messages defined by linq query, like this
<XmlIgnore>
Public Property messages As List(Of Message) = Msg.allMessages
<XmlElement("messages")>
Public Property messagesAllowDoNotShowAgain As List(Of Message) = Msg.allMessages.Where(Function(m) m.allowDoNotShowAgain).ToList()
When I right click a UserControl and select Properties, I want to create a custom property inside the UserControl properties that loads a file from an OpenFileDialog, like the ColumnDefinitions, but that browses inside my machine:
How can I achieve that? I've been searching but I'm a bit lost on where to start from.
NOTE: The image indicates that the property I want to create is one of the properties of the UserControl that appear when you Right click->Properties the UserControl.
Thanks!
I declared a property for searching execuble files in an OpenFileDialog in a WinForm project. The code is in VB .NET.
First create a Class like this:
Imports System.Drawing.Design
Imports System.Windows.Forms.Design
Imports System.Windows.Forms
Public Class ExecutableEditor : Inherits UITypeEditor
Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
Return UITypeEditorEditStyle.Modal
End Function
Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
If context Is Nothing And context.Instance Is Nothing And provider Is Nothing Then
Return value
End If
Dim editor_service As IWindowsFormsEditorService = _
CType(provider.GetService(GetType(IWindowsFormsEditorService)), _
IWindowsFormsEditorService)
If editor_service Is Nothing Then Return value
Dim ofdEjecutable As New OpenFileDialog
ofdEjecutable.Title = "Select an executable file"
ofdEjecutable.FileName = Nothing
ofdEjecutable.Filter = "executable file|*.exe"
If ofdEjecutable.ShowDialog = DialogResult.OK Then
Return ofdEjecutable.FileName
Else
Return Nothing
End If
End Function
End Class
Then in the code of the UserControl declare a property like this:
Private _executable As String
<Category("Injection")> _
<EditorAttribute(GetType(ExecutableEditor), GetType(UITypeEditor))> _
Public Property Executable As String
Get
Return _executable
End Get
Set(value As String)
_executable = value
End Set
End Property
What I got from your question is that you want a Browsable Property for you user control. Going by this, for simple .net property add:
private string myString;
[Browsable(true)]
[Category("Other")]
public string MyProperty { get { return myString; } set { myString = value; } }
and in setter of the property load the file after validation.
If you want it to be dependancy property do the same but move the code of loading the file in the propertychange handler.
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();
}
}
What are the requirements for a custom data source to be listed in the 'Data Source' drop-down list when adding a Dataset to a .rdlc report in Report Viewer 2010?
As can been seen from the screen grab, for some reason it is listing potential sources from a variety of referenced assemblies, but I can't see an obvious pattern as to why it is selecting these.
The 'GeneralDataSet' makes sense as that is a strongly-typed Dataset class, but I'm pretty sure most of the others are not, yet the design dialog still lists them.
I'm looking to roll my own custom data source and would prefer it to be selectable from this list.
I think it scans your project file looking for methods that return Lists<> and so on.
So something like:
public class Person
{
public string name { get; set; }
public int age { get; set; }
}
public class GetPeople
{
public List<Person> GetPeopleList()
{
return null;
}
public IEnumerable<Person> GetPeopleIEnumerable()
{
return null;
}
public IQueryable<Person> GetPeopleIQueryable()
{
return null;
}
}
All three show up, so take your pick. (Code is just thrashed out, ignore bad names/practices :))
But when you use a ReportViewer, you will need to manually set the datasets. Selecting it inside the report from what I have found just basically tells it what data to expect. So add an ObjectDataSource or just set it in the code behind.
I noticed the dataset does not appear if the source is exposed as a Property and not a method.
ie this fails to be a selectable data source.
public class FooData
{
public List<string> Data {get;set;}
}
but this will show up as a data source
public class FooData
{
public List<string> GetData();
}
I just had a problem with this also,
my class was returning Lists but would not show up in the datasources list.
I then added a parameterless constructor and it started to show up ( there was not one before ) I assmume this is so the reportviewer can create and instance of it.
eg:
public MyObject()
{
}
I've had a similar problem with custom lists which inherit from List.
You can work around it if your system will allow you to inherit without using interfaces. Ours doesn't.
The project containing this class WILL appear in the DataSource dropdown, and the class itself appears in the DataSet dropdown:
public class AccountList : List<AccountData>
{}
This class will NOT appear as a Dataset, which prevents its project from appearing as a DataSource (notice the "I" in front of AccountData):
public class AccountList : List<IAccountData>
{}
This is a pain because other aspects of our system require the lists to inherit from an interface not a concrete class. I don't know why it doesn't work.
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();
}