UWP Create Tile Menu Links - c#

I want to have for my UWP App on the Tile Menu some Deeplinks to specific things in my App.
Basicly i want to make the same like the XBOX App
Xbox tile menu
How do i create those links?

That's called the jump list, learn more here: https://learn.microsoft.com/en-us/uwp/api/windows.ui.startscreen.jumplist

You can use the Windows.UI.StartScreen.JumpList type to access the feautres of the app's jumplist. These actions then appear both in Start menu and in Task bar.
Using the SystemGroupKind property you can specify what should be displayed in the system area of the jump list - either Recent for recently opened files, Frequent for frequently opened items or None for nothing. To make this area alive, you need to use file type association for your app.
Then for your own custom items you utilize the Items property, where you can simply add new links -
// Create JumpListItem - first parameter is the activation argument,
// second the title of the task
var taskItem = JumpListItem.CreateWithArguments( "/Argument", "Write message");
// Set the description (optional)
taskItem.Description = "Write a message to someone.";
// Set the icon, URI must be ms-appx: or ms-appdata:
taskItem.Logo = new Uri("ms-appx:///Assets/WriteMessage.png");
// You may also specify a GroupName to group the tasks
return taskItem;
When the user clicks a task, you can check for the arguments in App.xaml.cs OnLaunched method:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
if (e.Kind == ActivationKind.Launch && e.Arguments == "/Argument")
{
// Navigate to specific method
}
}

Related

How to implement states on a windows form appliaction

I am developing a c# windows form application. In my application i have 3 forms (main form that has a list box and two buttons (Check in and check out), check in form and the check out form). On the main form, the list box contain user names, if a user select their name for the first time, the check in button must be enabled for the user to check in... But if the user checks in and then closes the application, when they reopen it, the button check out should be enabled and check in disabled.
I have been told to use the application/user states, but since I'm new in programming, i don't know how to implement the windows form states.
What should i do?
Thank you
There is no such thing as "Windows Forms states". You have several options to implement somthing like this, among which are:
Use a database (this makes sense if you have a varying number of users and a database server available)
Use user settings (this is a builtin mechanism of the .NET framework, but may not be suitable for lots of users)
Use a simple XML file to store the states of all users.
All three solutions require you to sort of "get into things". Write more about what you have available (database server, etc.) or whether you want a fixed number of users and I can extend this answer to help you get started.
I'm going to line out how to do number 2:
Create a little helper class that assigns a state to a user name:
public class UserState
{
public string UserName { get; set; }
public bool CheckedIn { get; set; }
public override string ToString() { return String.Format("{0}={1}", UserName, CheckedIn); }
}
This class allows you to store a user name and the checked in state and by calling ToString() get a value in the form "user=false".
Then, create a user scoped application setting (go to settings-tab of project settings and add a new setting of type System.Collections.Specialized.StringCollection) named UserStates. You can access this setting from code as Properties.Settings.Default.UserStates. It is basically a list of strings.
To add and persist a new entry you could do this:
UserState state = new UserState() { UserName = "Test", CheckedIn = false };
Properties.Settings.Default.UserStates.Add(state.ToString());
Properties.Settings.Default.Save();
The state for user "Test" (and the previously existing entries) are now stored across program restarts.
Now the idea is to build a list of users and their states when starting the program and to store this list when exiting.
Declare this as a member variable in the class:
private List<UserState> userStates = new List<UserState>();
Do the following in the form's OnLoad event:
if (Properties.Settings.Default.UserStates == null || Properties.Settings.Default.UserStates.Count == 0)
{
// Add your users to the collection initially. This is the first
// run of the application
userStates.Add(new UserState() { ... });
...
}
else
{
// Each line in the setting represents one user in the form name=state.
// We split each line into the parts and add them to the internal list.
for (int i = 0; i < Properties.Settings.Default.UserStates.Count; i++)
{
string stateLine = Properties.Settings.Default.UserStates[i];
string[] parts = stateLine.Split('=');
userStates.Add(new UserState() { UserName = parts[0].Trim(), CheckedIn = Boolean.Parse(parts[1].Trim()) });
}
}
This creates a new entry in an internal list of users for each stored line in the collection setting.
When a button is clicked, change the state in the respective UserState object in the list.
Do the following in the form's OnClose event:
// Create the collection from scratch
Properties.Settings.Default.UserStates = new System.Collections.Specialized.StringCollection();
// Add all the users and states from our internal list
foreach (UserState state in userStates)
{
Properties.Settings.Default.UserStates.Add(state.ToString());
}
// Save the settings for next start
Properties.Settings.Default.Save();
This persists the current list of user states to the setting.
Please note: I have tested this in Visual Studio now and it works. I leave the question of how to map the list box entries to the UserState objects in the internal list to you/as topic for a new question :-D
The downside of this approach: It is not very flexible - adding more states per user involves some coding.
It could be better for you to read about typed datasets and how to store/read them from XML. This gives you some sort of "database feeling" without actually having to use a database.

c# customizing controls on a save dialog -- how to disable parent folder button?

I am working from the sample project here: http://www.codeproject.com/Articles/8086/Extending-the-save-file-dialog-class-in-NET
I have hidden the address/location bar at the top and made other modifications but I can't for the life of me manage to disable the button that lets you go up to the parent folder. Ist is in the ToolbarWindow32 class which is the problem. This is what I have at the moment but it is not working:
int parentFolderWindow = GetDlgItem(parent, 0x440);
//Doesn't work
//ShowWindow((IntPtr)parentFolderWindow, SW_HIDE);
//40961 gathered from Spy++ watching messages when clicking on the control
// doesn't work
//SendMessage(parentFolderWindow, TB_ENABLEBUTTON, 40961, 0);
// doesn't work
//SendMessage(parentFolderWindow, TB_SETSTATE, 40961, 0);
//Comes back as '{static}', am I working with the wrong control maybe?
GetClassName((IntPtr)parentFolderWindow, lpClassName, (int)nLength);
Alternatively, if they do use the parent folder button and go where I don't want them to, I'm able to look at the new directory they land in, is there a way I can force the navigation to go back?
Edit: Added screenshot
//Comes back as '{static}', am I working with the wrong control maybe?
You know you are using the wrong control, you expected to see "ToolbarWindow32" back. A very significant problem, a common one for Codeproject.com code, is that this code cannot work anymore as posted. Windows has changed too much since 2004. Vista was the first version since then that added a completely new set of shell dialogs, they are based on IFileDialog. Much improved over its predecessor, in particular customizing the dialog is a lot cleaner through the IFileDialogCustomize interface. Not actually what you want to do, and customizations do not include tinkering with the navigation bar.
The IFileDialogEvents interface delivers events, the one you are looking for is the OnFolderChanging event. Designed to stop the user from navigating away from the current folder, the thing you really want to do.
While this looks good on paper, I should caution you about actually trying to use these interfaces. A common problem with anything related to the Windows shell is that they only made it easy to use from C++. The COM interfaces are the "unfriendly" kind, interfaces based on IUnknown without a type library you can use the easily add a reference to your C# or VB.NET project. Microsoft published the "Vista bridge" to make these interfaces usable from C# as well, it looks like this. Yes, yuck. Double yuck when you discover you have to do this twice, this only works on later Windows versions and there's a strong hint that you are trying to do this on XP (judging from the control ID you found).
This is simply not something you want to have to support. Since the alternative is so simple, use the supported .NET FileOk event instead. A Winforms example:
private void SaveButton_Click(object sender, EventArgs e) {
string requiredDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (var dlg = new SaveFileDialog()) {
dlg.InitialDirectory = requiredDir;
dlg.FileOk += (s, cea) => {
string selectedDir = System.IO.Path.GetDirectoryName(dlg.FileName);
if (string.Compare(requiredDir, selectedDir, StringComparison.OrdinalIgnoreCase) != 0) {
string msg = string.Format("Sorry, you cannot save to this directory.\r\nPlease select '{0}' instead", requiredDir);
MessageBox.Show(msg, "Invalid folder selection");
cea.Cancel = true;
}
};
if (dlg.ShowDialog() == DialogResult.OK) {
// etc...
}
}
}
I don't this is going to work. Even if you disable the button they can type ..\ and click save and it will take them up one level. You can't exactly disable the file name text box and maintain the functionality of the dialog.
You'd be better off either using the FolderBrowserDialog and setting it's RootFolder property and asking the user to type the filename in or auto generating it.
If the folder you are wanting to restrict the users to isn't an Environment.SpecialFolder Then you'll need to do some work to make the call to SHBrowseForFolder Manually using ILCreateFromPath to get a PIDLIST_ABSOLUTE for your path to pass to the BROWSEINFO.pidlRoot
You can reflect FolderBrowserDialog.RunDialog to see how to make that call.
Since you want such custom behaviors instead of developing low level code (that is likely yo break in the next versions of windows) you can try to develop your file picker form.
Basically it is a simple treeview + list view. Microsoft has a walk-through .
It will take you half a day but once you have your custom form you can define all behaviors you need without tricks and limits.

Application wide data context

This is more of a theory question than anything else, can't really show much in the way of code. However the topic is C# WPF.
So I have an application beginning with a main menu where I set a bunch of variables and load in some data from files and so on ready to begin the main program. I want this to be available to the main window that is going to be opened up.
Currently in my application I have it all set up by data context, an attempt at MVVM which I am very new to. This data context is linked to the menu window and allows me to set all the necessary data.
But how do I go about making that available to the new window. As far as I am aware a new data context is like a new object but in xaml, so if I were to create a data context in the next window all the information from it would be different?
I have always had trouble with things like this in all my learning of programming, I have data in one place but there is no sound way to link it across multiple windows/classes/objects etc.
Currently I have 4 files:
1 Holding all the data classes
2 My 'ViewModel' where I have the objects of these classes, property
updates, not too much
3 My menu with the bindings and data context and its code behind which is empty apart from some button
clicks
4 The main window that is going to use the data <-- this is my problem
First of all is this a correct approach, is there something different I should be thinking about? Can I implement a data context across two windows?
So I set up the context in the mainmenu window:
<Window.DataContext>
<local:WindowFunction x:Name="Interface"/>
</Window.DataContext>
And this links in my between file which has objects of the data.
class WindowFunction
{
protected PortInfo settings = new PortInfo();
protected FileInfo import = new FileInfo();
protected ObservableCollection<PersonName> lanes = new ObservableCollection<PersonName>();
public ObservableCollection<PersonName> Lane
{
get { return lanes; }
set { lanes = value; }
}
public PortInfo Settings
{
get { return settings; }
set { settings = value; }
}
public FileInfo Import
{
get { return import; }
set { import = value; }
}
}
I want to be able to call the information from this in another window. But if I create a new context the property paths will be pointing somewhere else surely?

Methods of manipulating/controling Windows Save As/Open File dialogs?

I'm attempting to build a Windows program that would provide a folder-bookmarks-ish functionality, that would allow you to hit a hotkey and navigate the dialog you have open to the folder assigned. Of course, to do this I'd need to be able to manipulate Windows Explorer dialogs and such. Anyone able to point me in the right direction?
Thanks in advance. :)
Looks like you will need to use pinvoke and get into the nitty gritty but it can be done.
http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy
I added a reference to SHDocVw Described Here: StackOverflow SHDocVw Example:
This will allow you to enumerate all of the open iexplore windows. (including the open Windows Explorer Dialogs; only issue is for certain special folders the full path is not displayed, but this can be remedied with a little creative code) You can then look through all of the open windows for URLs that have File:/// at the beginning, and then you can prompt the user to assign a hotkey for that specific open window. I've found that the SHDocVw does not reliably return all iexplore windows all the time, so this may not be the exact solution you are looking for. It would be easier to have the user type in the path of the Folder into a textbox on the Form, and then click a button that dynamically created a global hotkey and an event handler for the global hotkey keyboard hook. I attempted this a few different ways, and I ended up using a .cs file on codeproject Here: CodeProject: Low Level Global Keyboard Hook
Within the event Handler for the Global Keyboard Hook, you will have to use Process.Start(x.Process), where x is of a custom class type that has the specific hotkey associated with a specific Folders Location. That way you can look at the key that was pressed in the event handler, and start the associated Process (or in this case, open the specific folder) Each time the user adds an additional folder's location, a new object of custom type is created which includes the hotkey parameter and the folders Path (a user generated value). This custom object type (defined below) is then added to a global list of type "folderLocation" such that it can be accessed later when keys are actually pressed. The application added each folderLocation object to the flList as they were created.
I also defined a List of type Keys and then defined the first 12 objects in this list as F1...F12. For each folderlocation that is added, the next Key in the pre-defined list is added as the hotkey. (although you could also have the user define the hotkey)
In the end, the user presses F1, and the result is that the global key press event handler fires, and then the handler looks to see what button was pressed, compares it to the existing List of custom Types: folderLocation, and looks for a matching Key. Once Found, it then starts the associated folderLocation path using Process.Start.... Good Luck...
public class folderLocation
{
public string folderPath { get; set; }
public string folderName { get; set; }
public Keys hotKey { get; set; }
}

My SharePoint feature receiver activates a list definition feature, but my code cannot see the list template until the "second pass"

I am into my sixth hour battling with what hopefully should have a simple solution, so I thought I would post here.
I have an feature with a feature receiver whose sole purpose is to activate a deployed list definition feature and then create an instance of that new list definition.
The list definition feature, called "Custom Access List", is scoped at web.
So my feature receiver activates this list definition feature, having GUID "1E503BDA-803B-4a1a-A042-019FA1A70C4C":
...
string featureGuid = "1E503BDA-803B-4a1a-A042-019FA1A70C4C"; // my 'Custom try
{
SPFeatureCollection featureCollection = web.Features;
featureCollection.Add(new Guid(featureGUID), true); // activat the 'Custom Access List' feature
}
catch (Exception e)
{
// log exception
}
This code executes fine, and the list definition feature is activated, and the new list definition appears in the "Create" site menu option in the UI.
However, this is where my issue starts. The next line of my feature receiver code then tries to create an instance of this newly-available list:
SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; // exception! Value does not fall within the expected range
web.Lists.Add("My new custom access list","", listTemplate);
But the line SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; throws an exception with "Value does not fall within the expected range." - the list template, despite being deployed, visible and available in the UI under the "Create" site menu action, cannot be found in the receiver code.
Debugging the code confirms that the web.ListTemplates SPListTemplateCollection does not contain a entry for this new "Custom Access List", despite the UI suggesting otherwise.
And here is the weird thing. An exception is thrown, but if I then re-run the code i.e. reactivate the feature in the UI, to re-execute that feature receiver, the list template is then found -
SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; // found this time. It sees it the second time around
web.Lists.Add("My new custom access list","", listTemplate); // works fine
So, in a nutshell - initially, after activating a feature which, through receiver code, activates a list definition feature, that list definition is not visible until after a "postback" or some form of "SPWeb refresh". Then it is visible.
Am I missing something here? A call of web.Update() here:
try
{
SPFeatureCollection featureCollection = web.Features;
featureCollection.Add(new Guid(featureGUID), true); // true to force activation
web.Update();
}
...
does nothing. Is there some way I can "refresh" the SPWeb object so that the new list template can be seen and used?
The workaround I have found, for now, is to add the "Custom Access List" list template feature as an activation dependency in the "parent" feature receiver itself, and to make the "Custom Access List" list template feature hidden. That way, to my knowledge, the custom list definition feature is forcibly activated and I find that web.ListTemplates["Custom Access List"]; is found.
But I would much rather the former approach work - to activate, in my receiver code, the list definition feature and then to find it so that an instance of the list can then be created.
Andrew,
The problem is to do with internal async events and the timing of the activity. As you say if you go away and come back it works - i.e. the async event has completed. You are treating the featureCollection.Add as a synchronus method.
What you really should be doing if you need a template and a list instance created at the same time is using the XML framework for this.
Add a to your feature that has the list template, or alternatively add a new feature for the list instance and reference the FeatureID of the list template.
Andrew
You need to call EnsureListsData on the SPListCollection that you just updated.
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistcollection.ensurelistsdata.aspx
Seems that the list template is not yet created. You can try to do a loop and wait to be created
using(SPWeb web = site.OpenWeb())
{
SPListTemplate listTemplate = null;
while (listTemplate == null)
{
Thread.Sleep(1000);
try
{
listTemplate = web.ListTemplates["Custom Access List"];
if (listTemplate != null)
{
// here your code
web.Lists.Add("My new custom access list", "", listTemplate);
}
}
catch
{
web = site.OpenWeb();
}
}
}

Categories

Resources