Create WinUI3/MVVM Most Recently Used (MRU) List in Menu Bar - mvvm

I would like to create a classic "Recent Files" list in my Windows app menu bar (similar to Visual Studio's menu bar -> File -> Recent Files -> see recent files list)
The MRU list (List < string > myMRUList...) is known and is not in focus of this question. The problem is how to display and bind/interact with the list according to the MVVM rules.
Microsoft.Toolkit.Uwp.UI.Controls's Menu class will be removed in a future release and they recommend to use MenuBar control from the WinUI. I haven't found any examples, that use WinUI's MenuBar to create a "Recent Files" list.
I'm using Template Studio to create a WinUI 3 app. In the ShellPage.xaml I added
<MenuFlyoutSubItem x:Name="mruFlyout" Text="Recent Files"></MenuFlyoutSubItem>
and in ShellPage.xaml.c
private void Button_Click(object sender, RoutedEventArgs e)
{
mruFlyout.Items.Insert(mruFlyout.Items.Count, new MenuFlyoutItem(){ Text = "C:\\Test1_" + DateTime.Now.ToString("MMMM dd") } );
mruFlyout.Items.Insert(mruFlyout.Items.Count, new MenuFlyoutItem(){ Text = "C:\\Test2_" + DateTime.Now.ToString("MMMM dd") } );
mruFlyout.Items.Insert(mruFlyout.Items.Count, new MenuFlyoutItem(){ Text = "C:\\Test3_" + DateTime.Now.ToString("MMMM dd") } );
}
knowing this is not MVVM, but even this approach does not work properly, because the dynamically generated MenuFlyoutItem can be updated only once by Button_Click() event.
Could anybody give me an example, how to create the "Recent Files" functionality, but any help would be great! Thanks

Unfortunately, it seems that there is no better solution than handling this in code behind since the Items collection is readonly and also doesn't response to changes in the UI Layout.
In addition to that, note that because of https://github.com/microsoft/microsoft-ui-xaml/issues/7797, updating the Items collection does not get reflected until the Flyout has been closed and reopened.
So assuming your ViewModel has an ObservableCollection, I would probably do this:
// 1. Register collection changed
MyViewModel.RecentFiles.CollectionChanged += RecentFilesChanged;
// 2. Handle collection change
private void RecentFilesChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// 3. Create new UI collection
var flyoutItems = list.Select(entry =>
new MenuFlyoutItem()
{
Text = entry.Name
}
);
// 4. Updating your MenuFlyoutItem
mruFlyout.Items.Clear();
flyoutItems.ForEach(entry => mruFlyout.Items.Add(entry));
}

Based on chingucoding's answer I got to the "recent files list" binding working.
For completeness I post the detailed code snippets here (keep in mind, that I'm not an expert):
Again using Template Studio to create a WinUI 3 app.
ShellViewModel.cs
// constructor
public ShellViewModel(INavigationService navigationService, ILocalSettingsService localSettingsService)
{
...
MRUUpdateItems();
}
ShellViewModel_RecentFiles.cs ( <-- partial class )
using System.Collections.ObjectModel;
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.Storage.Pickers;
namespace App_MostRecentUsedTest.ViewModels;
public partial class ShellViewModel : ObservableRecipient
{
public ObservableCollection<MRUItem> MRUItems{ get; set;} = new();
// update ObservableCollection<MRUItem>MRUItems from MostRecentlyUsedList
public void MRUUpdateItems()
{
var mruTokenList = StorageApplicationPermissions.MostRecentlyUsedList.Entries.Select(entry => entry.Token).ToList();
var mruMetadataList = StorageApplicationPermissions.MostRecentlyUsedList.Entries.Select(entry => entry.Metadata).ToList(); // contains path as string
MRUItems.Clear(); var i = 0;
foreach (var path in mruMetadataList)
{
MRUItems.Add(new MRUItem() { Path = path, Token = mruTokenList[i++] });
}
}
// called if user selects a recent used file from menu bar list
[RelayCommand]
protected async Task MRULoadFileClicked(int? fileId)
{
if (fileId is not null)
{
var mruItem = MRUItems[(int)fileId];
FileInfo fInfo = new FileInfo(mruItem.Path ?? "");
if (fInfo.Exists)
{
StorageFile? file = await Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(mruItem.Token);
if (file is not null)
{
Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(file, file.Path); // store file.Path into Metadata
MRUUpdateItems();
// LOAD_FILE(file);
}
}
else
{
}
}
await Task.CompletedTask;
}
[RelayCommand]
protected async Task MenuLoadFileClicked()
{
StorageFile? file = await GetFilePathAsync();
if (file is not null)
{
Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(file, file.Path); // store file.Path into Metadata
MRUUpdateItems();
// LOAD_FILE(file);
}
await Task.CompletedTask;
}
// get file path with filePicker
private async Task<StorageFile?> GetFilePathAsync()
{
FileOpenPicker filePicker = new();
filePicker.FileTypeFilter.Add(".txt");
IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(filePicker, hwnd);
return await filePicker.PickSingleFileAsync();
}
public class MRUItem : INotifyPropertyChanged
{
private string? path;
private string? token;
public string? Path
{
get => path;
set
{
path = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(path));
}
}
public string? Token
{
get => token;
set => token = value;
}
public event PropertyChangedEventHandler? PropertyChanged;
}
}
ShellPage.xaml
<MenuBar>
<MenuBarItem x:Name="ShellMenuBarItem_File">
<MenuFlyoutItem x:Uid="ShellMenuItem_File_Load" Command="{x:Bind ViewModel.MenuLoadFileClickedCommand}" />
<MenuFlyoutSubItem x:Name="MRUFlyout" Text="Recent Files..." />
</MenuBarItem>
</MenuBar>
ShellPage.xaml.cs
// constructor
public ShellPage(ShellViewModel viewModel)
{
...
// MRU initialziation
// assign RecentFilesChanged() to CollectionChanged-event
ViewModel.MRUItems.CollectionChanged += RecentFilesChanged;
// Add (and RemoveAt) trigger RecentFilesChanged-event to update MenuFlyoutItems
ViewModel.MRUItems.Add(new MRUItem() { Path = "", Token = ""});
ViewModel.MRUItems.RemoveAt(ViewModel.MRUItems.Count - 1);
}
// MRU Handle collection change
private void RecentFilesChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// project each MRUItems list element into a new UI MenuFlyoutItem flyoutItems list
var i = 0;
var flyoutItems = ViewModel.MRUItems.Select(entry =>
new MenuFlyoutItem()
{
Text = " " + i.ToString() + " " + FilenameHelper.EllipsisString(entry.Path, 65),
Command = ViewModel.MRULoadFileClickedCommand,
CommandParameter = i++
}
);
//// If you want to update the list while it is shown,
//// you will need to create a new FlyoutItem because of
//// https://github.com/microsoft/microsoft-ui-xaml/issues/7797
// Create a new flyout and populate it
var newFlyout = new MenuFlyoutSubItem();
newFlyout.Text = MRUFlyout.Text; // Text="Recent Files...";
// Updating your MenuFlyoutItem
flyoutItems.ToList().ForEach(item => newFlyout.Items.Add(item));
// Get index of old sub item and remove it
var oldIndex = ShellMenuBarItem_File.Items.IndexOf(MRUFlyout);
ShellMenuBarItem_File.Items.Remove(MRUFlyout);
// Insert the new flyout at the correct position
ShellMenuBarItem_File.Items.Insert(oldIndex, newFlyout);
// Assign newFlyout to "old"-MRUFlyout
MRUFlyout = newFlyout;
}

Related

Use PopupExtensions.ShowPopupAsync function in Custom Control in MAUI

I created a custom control in MAUI that must work if user select with a click or tap, a Popup must show with some content, let's say for example a Calculator instead a Keyboard. I'm using CommunityToolkit.Maui. But the sentence
var popup = new PickerControl();
var result = await PopupExtensions.ShowPopupAsync<PickerControl>(this, popup);
throw me an error because this in inside the control and expects a Page, so need to know how handle the page or parent page in the same control. Picker control is the Popup with the content.
The code:
public partial class EntryCalculator : Frame
{
TapGestureRecognizer _tapGestureRecognizer;
public EntryCalculator()
{
InitializeComponent();
}
///Properties here
private void Initialize()
{
_tapGestureRecognizer = new TapGestureRecognizer();
}
private async static void IsDisplayPickerPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var controls = (EntryCalculator)bindable;
if (newValue != null)
{
if ((bool)newValue)
{
var popup = new PickerControl();
var response = PopupExtensions.ShowPopupAsync<PickerControl>(this, popup);
if (response != null && response is decimal)
{
controls.Value = (decimal)response;
}
}
}
}
///... other methods
At first, you can get the current page from the navigation stack:
If you use the shell:
Page currentpage = Shell.Current.Navigation.NavigationStack.LastOrDefault();
If you use the NavigationPage:
Page currentpage = Navigation.NavigationStack.LastOrDefault();
Or just only use:Page currentpage = App.Current.MainPage.Navigation.NavigationStack.LastOrDefault();. The App.Current.MainPage will be the Shell or the NavigationPage, it depends on what you used in your project.
In addition, you can get the current page from the custom control. Such as:
public static class ViewExtensions
{
/// <summary>
/// Gets the page to which an element belongs
/// </summary>
/// <returns>The page.</returns>
/// <param name="element">Element.</param>
public static Page GetParentPage (this VisualElement element)
{
if (element != null) {
var parent = element.Parent;
while (parent != null) {
if (parent is Page) {
return parent as Page;
}
parent = parent.Parent;
}
}
return null;
}
}

VSCode: Create a document in memory with URI for automated testing?

Background
I created an extension that interacts with documents. In order to test the extension I need to create documents, that the extension can work with. The extension has to access the document via uri.
Currently I'm using vscode.workspace.openTextDocument({content: _content, language: _language}); for document creation. The problem is, it does not have a valid URI.
Question
How can I create a virtual document in memory, that has a valid URI?
As there was no native solution to this, I created my and I'd like to share it here:
A TextDocumentContentProvider for files in memory. Example usage shown below
memoryfile.ts
import * as vscode from 'vscode';
const _SCHEME = "inmemoryfile";
/**
* Registration function for In-Memory files.
* You need to call this once, if you want to make use of
* `MemoryFile`s.
**/
export function register_memoryFileProvider ({ subscriptions }: vscode.ExtensionContext)
{
const myProvider = new (class implements vscode.TextDocumentContentProvider
{
provideTextDocumentContent(uri: vscode.Uri): string
{
let memDoc = MemoryFile.getDocument (uri);
if (memDoc == null)
return "";
return memDoc.read ();
}
})();
subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(
_SCHEME, myProvider));
}
/**
* Management class for in-memory files.
**/
class MemoryFileManagement
{
private static _documents: {[key: string]: MemoryFile} = {};
private static _lastDocId: number = 0;
public static getDocument(uri: vscode.Uri) : MemoryFile | null
{
return MemoryFileManagement._documents[uri.path];
}
private static _getNextDocId(): string{
MemoryFileManagement._lastDocId++;
return "_" + MemoryFileManagement._lastDocId + "_";
}
public static createDocument(extension = "")
{
let path = MemoryFileManagement._getNextDocId ();
if (extension != "")
path += "." + extension;
let self = new MemoryFile(path);
MemoryFileManagement._documents[path] = self;
return self;
}
}
/**
* A file in memory
**/
export class MemoryFile
{
/******************
** Static Area **
******************/
public static getDocument(uri: vscode.Uri) : MemoryFile | null {
return MemoryFileManagement.getDocument (uri);
}
public static createDocument(extension = "") {
return MemoryFileManagement.createDocument (extension);
}
/******************
** Object Area **
******************/
public content: string = "";
public uri: vscode.Uri;
constructor (path: string)
{
this.uri = vscode.Uri.from ({scheme: _SCHEME, path: path})
}
public write(strContent: string){
this.content += strContent;
}
public read(): string {
return this.content;
}
public getUri(): vscode.Uri {
return this.uri;
}
}
Example usage
Register the provider
You need to register the provider somewhere in the beginning of your test code (I do it in index.ts before Mocha is instantiated):
register_memoryFileProvider (extensionContext);
(How do I get the extension context?)
Create a document
Creating and using a file works as follows:
// create the in-memory document
let memfile = MemoryFile.createDocument ("ts");
memfile.write ("my content");
// create a vscode.TextDocument from the in-memory document.
let doc = await vscode.workspace.openTextDocument (memfile.getUri ());
Notes
Be aware, that LSP commands might not work with with approach, because they might be registered to a certain specific schema.
As rioV8 said, you can also use an existing document and change its content. Here the code:
export class TmpFile
{
private static _lastDocId: number = 0;
private static _getNextDocId(): string{
this._lastDocId++;
return "tmpfile_" + this._lastDocId;
}
public static async createDocument(strContent: string, extension:string = "")
: Promise<vscode.TextDocument | null>
{
let folder = "/tmp"
let filename = this._getNextDocId ();
let ext = (extension != "" ? "." + extension : "");
const newFile = vscode.Uri.parse('untitled:' + path.join(folder, filename + ext));
{
const edit = new vscode.WorkspaceEdit();
edit.insert(newFile, new vscode.Position(0, 0), strContent);
let success = await vscode.workspace.applyEdit(edit);
if (!success)
return null;
}
let document = await vscode.workspace.openTextDocument(newFile);
return document;
}
}
Pro's
It's a file (schema), so all LSP commands will work
The path (used above) does not even need to exist.
Con's
The file is really opened in the editor. You need to close it later
The file is a changed file in the editor, so it will ask you to save the changes upon closing.
Files cannot be closed in vscode. You can only run:
vscode.window.showTextDocument(doc.uri, {preview: true, preserveFocus: false})
.then(() => {
return vscode.commands.executeCommand('workbench.action.closeActiveEditor');
});
```<br>
which is a rather nasty workaround.

VisualForce Button not returning Selected Ids

I am converting a custom List JS button to support lighting. So, I've made changes to existing class and created a VF page and added that to the list view button. But when I run the functionality nothing seems to happen and debug logs returned Id as 000000.. Pls suggest.
global class AddUserToTeam{
public Opportunity objOpp;
global AddUserToTeam(ApexPages.StandardSetController stdcontroller) {
objOpp = (Opportunity)stdController.getRecord();
system.debug(objOpp );
}
public pagereference addTeam(){
List<Id> opportunityIds = new List<Id>();
opportunityIds.add(objOpp.Id);
system.debug('oppid'+ opportunityIds);
addTeamMember(opportunityIds);
//return new pagereference(url.getsalesforcebaseurl().toexternalform()+'/'+objOpp.Id);
return new PageReference('/006/o');
}
webservice static boolean addTeamMember(List<Id> opptyIds)
{
// some logic to add a user to teams
}
VF
<apex:page standardController="Opportunity" recordSetVar="Opportunities" extensions="AddUserToTeam" action="{!addTeam}">
</apex:page>
[enter image description here][1]
[1]: https://i.stack.imgur.com/2V3vp.png
I fixed the issue, check the below code
global class AddUserToTeam{
public Opportunity objOpp;
public String accIds{get;set;}
global AddUserToTeam(ApexPages.StandardSetController stdcontroller) {
System.debug('Get Selected');
objOpp = stdcontroller.getSelected();
accIds = '';
for(Opportunity acc : objOpp){
accIds += acc.Id + ',';
System.debug('Opp ID : '+accIds);
}
accIds = accIds.removeEnd(',');
}
}
public pagereference addTeam(){
List<Id> opportunityIds = new List<Id>();
opportunityIds.add(accIds );
system.debug('oppid'+ opportunityIds);
addTeamMember(opportunityIds);
return new pagereference(url.getsalesforcebaseurl().toexternalform()+'/'+accIds );
//return new PageReference('/006/o');
}
webservice static boolean addTeamMember(List<Id> opptyIds)
{
// some logic to add a user to teams
}

Powershell - How to print rendered HTML to a network printer? [duplicate]

I would like to create a function in C# that takes a specific webpage and coverts it to a JPG image from within ASP.NET. I don't want to do this via a third party or thumbnail service as I need the full image. I assume I would need to somehow leverage the webbrowser control from within ASP.NET but I just can't see where to get started. Does anyone have examples?
Ok, this was rather easy when I combined several different solutions:
These solutions gave me a thread-safe way to use the WebBrowser from ASP.NET:
http://www.beansoftware.com/ASP.NET-Tutorials/Get-Web-Site-Thumbnail-Image.aspx
http://www.eggheadcafe.com/tutorials/aspnet/b7cce396-e2b3-42d7-9571-cdc4eb38f3c1/build-a-selfcaching-asp.aspx
This solution gave me a way to convert BMP to JPG:
Bmp to jpg/png in C#
I simply adapted the code and put the following into a .cs:
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Windows.Forms;
public class WebsiteToImage
{
private Bitmap m_Bitmap;
private string m_Url;
private string m_FileName = string.Empty;
public WebsiteToImage(string url)
{
// Without file
m_Url = url;
}
public WebsiteToImage(string url, string fileName)
{
// With file
m_Url = url;
m_FileName = fileName;
}
public Bitmap Generate()
{
// Thread
var m_thread = new Thread(_Generate);
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _Generate()
{
var browser = new WebBrowser { ScrollBarsEnabled = false };
browser.Navigate(m_Url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Capture
var browser = (WebBrowser)sender;
browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.BringToFront();
browser.DrawToBitmap(m_Bitmap, browser.Bounds);
// Save as file?
if (m_FileName.Length > 0)
{
// Save
m_Bitmap.SaveJPG100(m_FileName);
}
}
}
public static class BitmapExtensions
{
public static void SaveJPG100(this Bitmap bmp, string filename)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static void SaveJPG100(this Bitmap bmp, Stream stream)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageDecoders();
foreach (var codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
// Return
return null;
}
}
And can call it as follows:
WebsiteToImage websiteToImage = new WebsiteToImage( "http://www.cnn.com", #"C:\Some Folder\Test.jpg");
websiteToImage.Generate();
It works with both a file and a stream. Make sure you add a reference to System.Windows.Forms to your ASP.NET project. I hope this helps.
UPDATE: I've updated the code to include the ability to capture the full page and not require any special settings to capture only a part of it.
Good solution by Mr Cat Man Do.
I've needed to add a row to suppress some errors that came up in some webpages
(with the help of an awesome colleague of mine)
private void _Generate()
{
var browser = new WebBrowser { ScrollBarsEnabled = false };
browser.ScriptErrorsSuppressed = true; // <--
browser.Navigate(m_Url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
}
...
Thanks Mr Do
Here is my implementation using extension methods and task factory instead thread:
/// <summary>
/// Convert url to bitmap byte array
/// </summary>
/// <param name="url">Url to browse</param>
/// <param name="width">width of page (if page contains frame, you need to pass this params)</param>
/// <param name="height">heigth of page (if page contains frame, you need to pass this params)</param>
/// <param name="htmlToManipulate">function to manipulate dom</param>
/// <param name="timeout">in milliseconds, how long can you wait for page response?</param>
/// <returns>bitmap byte[]</returns>
/// <example>
/// byte[] img = new Uri("http://www.uol.com.br").ToImage();
/// </example>
public static byte[] ToImage(this Uri url, int? width = null, int? height = null, Action<HtmlDocument> htmlToManipulate = null, int timeout = -1)
{
byte[] toReturn = null;
Task tsk = Task.Factory.StartNew(() =>
{
WebBrowser browser = new WebBrowser() { ScrollBarsEnabled = false };
browser.Navigate(url);
browser.DocumentCompleted += (s, e) =>
{
var browserSender = (WebBrowser)s;
if (browserSender.ReadyState == WebBrowserReadyState.Complete)
{
if (htmlToManipulate != null) htmlToManipulate(browserSender.Document);
browserSender.ClientSize = new Size(width ?? browser.Document.Body.ScrollRectangle.Width, height ?? browser.Document.Body.ScrollRectangle.Bottom);
browserSender.ScrollBarsEnabled = false;
browserSender.BringToFront();
using (Bitmap bmp = new Bitmap(browserSender.Document.Body.ScrollRectangle.Width, browserSender.Document.Body.ScrollRectangle.Bottom))
{
browserSender.DrawToBitmap(bmp, browserSender.Bounds);
toReturn = (byte[])new ImageConverter().ConvertTo(bmp, typeof(byte[]));
}
}
};
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
tsk.Wait(timeout);
return toReturn;
}
There is a good article by Peter Bromberg on this subject here. His solution seems to do what you need...
The solution is perfect, just needs a fixation in the line which sets the WIDTH of the image. For pages with a LARGE HEIGHT, it does not set the WIDTH appropriately:
//browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.ClientSize = new Size(1000, browser.Document.Body.ScrollRectangle.Bottom);
And for adding a reference to System.Windows.Forms, you should do it in .NET-tab of ADD REFERENCE instead of COM -tab.
You could use WatiN to open a new browser, then capture the screen and crop it appropriately.

Netbeans lookup not getting executed first time when the application is started

I have an application in which lookup provider is in explorer window and it is a jcomboBox. Its selected value is provided as lookup to other top components and displayed one in editor and one in output window area. The value of the jcombobox is saved at the time of closing the application and initialized into the jcombobox when the application is started.
When I clean and build the application and start the application, the initial value displayed in the jcombobox is not updated in the lookup and listner windows display uninitialized values. Once the new value is selected in the jcombobox it gets displayed in the other windows.
If I close the application without changing the value of the jcombobox and start the application, the lookup is not updated.
If I change the selection in the combobox, close the application and start again, the lookup gets updated.
I expect anytime when the application is started, the other windows will get the value of the lookup. Any help in this regards will be appreciated. Thanks in advance.
The code for the explorer window which provides the lookup is as follows:
public final class ProviderTopComponent extends TopComponent {
public ProviderTopComponent() {
initComponents();
setName(Bundle.CTL_ProviderTopComponent());
setToolTipText(Bundle.HINT_ProviderTopComponent());
associateLookup(new AbstractLookup(content));
}
private void initComponents() {
jComboBox1 = new javax.swing.JComboBox();
jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
jComboBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jComboBox1ActionPerformed(evt);
}
});
private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {
str = (String) jComboBox1.getSelectedItem();
content.set(Collections.singleton(str), null);
}
private final InstanceContent content = new InstanceContent();
String str;
// Variables declaration - do not modify
private javax.swing.JComboBox jComboBox1;
void writeProperties(java.util.Properties p) {
// better to version settings since initial version as advocated at
// http://wiki.apidesign.org/wiki/PropertyFiles
p.setProperty("version", "1.0");
p.setProperty("val", (String) jComboBox1.getSelectedItem());
}
void readProperties(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
String v = p.getProperty("val");
if(v != null) {
jComboBox1.setSelectedItem(v);
}
}
}
The code for the lookup listener window is as follows:
public final class Listner_1TopComponent extends TopComponent implements LookupListener{
public Listner_1TopComponent() {
initComponents();
setName(Bundle.CTL_editorTopComponent());
setToolTipText(Bundle.HINT_editorTopComponent());
}
...
private void initComponents() {
...
jLabel1 = new javax.swing.JLabel();
...
Collection<? extends String> str_collection;
private Lookup.Result<String> result = null;
String str;
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
// End of variables declaration
#Override
public void componentOpened() {
result = org.openide.util.Utilities.actionsGlobalContext().lookupResult(String.class);
result.addLookupListener(this);
}
#Override
public void componentClosed() {
result.removeLookupListener(this);
}
#Override
public void resultChanged(LookupEvent le) {
str_collection = result.allInstances();
if (str_collection.isEmpty()) {
} else {
str = str_collection.iterator().next();
}
jLabel1.setText(str);
jLabel1.repaint();
}
}